git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
authorPaul Cercueil <paul@crapouillou.net>
Sun, 9 Jul 2023 12:38:25 +0000 (14:38 +0200)
committerPaul Cercueil <paul@crapouillou.net>
Sun, 23 Jul 2023 17:44:28 +0000 (19:44 +0200)
subrepo:
  subdir:   "deps/libretro-common"
  merged:   "86d5e4128c"
upstream:
  origin:   "https://github.com/libretro/libretro-common.git"
  branch:   "master"
  commit:   "86d5e4128c"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"

393 files changed:
deps/libretro-common/.gitignore [new file with mode: 0644]
deps/libretro-common/.gitrepo [new file with mode: 0644]
deps/libretro-common/Makefile.test [new file with mode: 0644]
deps/libretro-common/audio/audio_mix.c [new file with mode: 0644]
deps/libretro-common/audio/audio_mixer.c [new file with mode: 0644]
deps/libretro-common/audio/conversion/float_to_s16.c [new file with mode: 0644]
deps/libretro-common/audio/conversion/float_to_s16_neon.S [new file with mode: 0644]
deps/libretro-common/audio/conversion/float_to_s16_neon.c [new file with mode: 0644]
deps/libretro-common/audio/conversion/mono_to_stereo_float.c [new file with mode: 0644]
deps/libretro-common/audio/conversion/s16_to_float.c [new file with mode: 0644]
deps/libretro-common/audio/conversion/s16_to_float_neon.S [new file with mode: 0644]
deps/libretro-common/audio/conversion/s16_to_float_neon.c [new file with mode: 0644]
deps/libretro-common/audio/conversion/stereo_to_mono_float.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filter.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/BassBoost.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/ChipTune-Lowpass.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/ChipTuneEnhance.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Chorus.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Crystalizer.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/EQ.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Echo.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/EchoReverb.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/HighShelfDampen.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/IIR.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/LowPassCPS.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Makefile [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Mono.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Panning.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Phaser.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Reverb.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Tremolo.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/Vibrato.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/WahWah.dsp [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/chorus.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/configure [new file with mode: 0755]
deps/libretro-common/audio/dsp_filters/crystalizer.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/echo.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/eq.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/fft/fft.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/fft/fft.h [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/iir.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/link.T [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/panning.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/phaser.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/reverb.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/tremolo.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/vibrato.c [new file with mode: 0644]
deps/libretro-common/audio/dsp_filters/wahwah.c [new file with mode: 0644]
deps/libretro-common/audio/resampler/audio_resampler.c [new file with mode: 0644]
deps/libretro-common/audio/resampler/drivers/nearest_resampler.c [new file with mode: 0644]
deps/libretro-common/audio/resampler/drivers/sinc_resampler.c [new file with mode: 0644]
deps/libretro-common/audio/resampler/drivers/sinc_resampler_neon.S [new file with mode: 0644]
deps/libretro-common/cdrom/cdrom.c [new file with mode: 0644]
deps/libretro-common/compat/compat_fnmatch.c [new file with mode: 0644]
deps/libretro-common/compat/compat_getopt.c [new file with mode: 0644]
deps/libretro-common/compat/compat_ifaddrs.c [new file with mode: 0644]
deps/libretro-common/compat/compat_posix_string.c [new file with mode: 0644]
deps/libretro-common/compat/compat_snprintf.c [new file with mode: 0644]
deps/libretro-common/compat/compat_strcasestr.c [new file with mode: 0644]
deps/libretro-common/compat/compat_strl.c [new file with mode: 0644]
deps/libretro-common/compat/compat_strldup.c [new file with mode: 0644]
deps/libretro-common/compat/compat_vscprintf.c [new file with mode: 0644]
deps/libretro-common/compat/fopen_utf8.c [new file with mode: 0644]
deps/libretro-common/crt/include/string.h [new file with mode: 0644]
deps/libretro-common/crt/string.c [new file with mode: 0644]
deps/libretro-common/dynamic/dylib.c [new file with mode: 0644]
deps/libretro-common/encodings/encoding_base64.c [new file with mode: 0644]
deps/libretro-common/encodings/encoding_crc32.c [new file with mode: 0644]
deps/libretro-common/encodings/encoding_utf.c [new file with mode: 0644]
deps/libretro-common/features/features_cpu.c [new file with mode: 0644]
deps/libretro-common/file/archive_file.c [new file with mode: 0644]
deps/libretro-common/file/archive_file_7z.c [new file with mode: 0644]
deps/libretro-common/file/archive_file_zlib.c [new file with mode: 0644]
deps/libretro-common/file/config_file.c [new file with mode: 0644]
deps/libretro-common/file/config_file_userdata.c [new file with mode: 0644]
deps/libretro-common/file/file_path.c [new file with mode: 0644]
deps/libretro-common/file/file_path_io.c [new file with mode: 0644]
deps/libretro-common/file/nbio/nbio_intf.c [new file with mode: 0644]
deps/libretro-common/file/nbio/nbio_linux.c [new file with mode: 0644]
deps/libretro-common/file/nbio/nbio_orbis.c [new file with mode: 0644]
deps/libretro-common/file/nbio/nbio_stdio.c [new file with mode: 0644]
deps/libretro-common/file/nbio/nbio_unixmmap.c [new file with mode: 0644]
deps/libretro-common/file/nbio/nbio_windowsmmap.c [new file with mode: 0644]
deps/libretro-common/file/retro_dirent.c [new file with mode: 0644]
deps/libretro-common/formats/bmp/rbmp.c [new file with mode: 0644]
deps/libretro-common/formats/bmp/rbmp_encode.c [new file with mode: 0644]
deps/libretro-common/formats/cdfs/cdfs.c [new file with mode: 0644]
deps/libretro-common/formats/image_texture.c [new file with mode: 0644]
deps/libretro-common/formats/image_transfer.c [new file with mode: 0644]
deps/libretro-common/formats/jpeg/rjpeg.c [new file with mode: 0644]
deps/libretro-common/formats/json/rjson.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_bitstream.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_cdrom.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_chd.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_flac.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_flac_codec.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_huffman.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_lzma.c [new file with mode: 0644]
deps/libretro-common/formats/libchdr/libchdr_zlib.c [new file with mode: 0644]
deps/libretro-common/formats/logiqx_dat/logiqx_dat.c [new file with mode: 0644]
deps/libretro-common/formats/m3u/m3u_file.c [new file with mode: 0644]
deps/libretro-common/formats/png/rpng.c [new file with mode: 0644]
deps/libretro-common/formats/png/rpng_encode.c [new file with mode: 0644]
deps/libretro-common/formats/png/rpng_internal.h [new file with mode: 0644]
deps/libretro-common/formats/tga/rtga.c [new file with mode: 0644]
deps/libretro-common/formats/wav/rwav.c [new file with mode: 0644]
deps/libretro-common/formats/xml/rxml.c [new file with mode: 0644]
deps/libretro-common/formats/xml/test/Makefile [new file with mode: 0644]
deps/libretro-common/formats/xml/test/rxml_test.c [new file with mode: 0644]
deps/libretro-common/gfx/gl_capabilities.c [new file with mode: 0644]
deps/libretro-common/gfx/scaler/pixconv.c [new file with mode: 0644]
deps/libretro-common/gfx/scaler/scaler.c [new file with mode: 0644]
deps/libretro-common/gfx/scaler/scaler_filter.c [new file with mode: 0644]
deps/libretro-common/gfx/scaler/scaler_int.c [new file with mode: 0644]
deps/libretro-common/glsm/glsm.c [new file with mode: 0644]
deps/libretro-common/glsym/README.md [new file with mode: 0644]
deps/libretro-common/glsym/glgen.py [new file with mode: 0755]
deps/libretro-common/glsym/glsym_es2.c [new file with mode: 0644]
deps/libretro-common/glsym/glsym_es3.c [new file with mode: 0644]
deps/libretro-common/glsym/glsym_gl.c [new file with mode: 0644]
deps/libretro-common/glsym/rglgen.c [new file with mode: 0644]
deps/libretro-common/glsym/rglgen.py [new file with mode: 0755]
deps/libretro-common/glsym/xglgen.py [new file with mode: 0644]
deps/libretro-common/hash/lrc_hash.c [new file with mode: 0644]
deps/libretro-common/include/array/rbuf.h [new file with mode: 0644]
deps/libretro-common/include/array/rhmap.h [new file with mode: 0644]
deps/libretro-common/include/audio/audio_mix.h [new file with mode: 0644]
deps/libretro-common/include/audio/audio_mixer.h [new file with mode: 0644]
deps/libretro-common/include/audio/audio_resampler.h [new file with mode: 0644]
deps/libretro-common/include/audio/conversion/dual_mono.h [new file with mode: 0644]
deps/libretro-common/include/audio/conversion/float_to_s16.h [new file with mode: 0644]
deps/libretro-common/include/audio/conversion/s16_to_float.h [new file with mode: 0644]
deps/libretro-common/include/audio/dsp_filter.h [new file with mode: 0644]
deps/libretro-common/include/boolean.h [new file with mode: 0644]
deps/libretro-common/include/cdrom/cdrom.h [new file with mode: 0644]
deps/libretro-common/include/clamping.h [new file with mode: 0644]
deps/libretro-common/include/compat/apple_compat.h [new file with mode: 0644]
deps/libretro-common/include/compat/fnmatch.h [new file with mode: 0644]
deps/libretro-common/include/compat/fopen_utf8.h [new file with mode: 0644]
deps/libretro-common/include/compat/getopt.h [new file with mode: 0644]
deps/libretro-common/include/compat/ifaddrs.h [new file with mode: 0644]
deps/libretro-common/include/compat/intrinsics.h [new file with mode: 0644]
deps/libretro-common/include/compat/msvc.h [new file with mode: 0644]
deps/libretro-common/include/compat/msvc/stdint.h [new file with mode: 0644]
deps/libretro-common/include/compat/posix_string.h [new file with mode: 0644]
deps/libretro-common/include/compat/strcasestr.h [new file with mode: 0644]
deps/libretro-common/include/compat/strl.h [new file with mode: 0644]
deps/libretro-common/include/compat/zconf.h [new file with mode: 0644]
deps/libretro-common/include/compat/zconf.h.in [new file with mode: 0644]
deps/libretro-common/include/compat/zlib.h [new file with mode: 0644]
deps/libretro-common/include/compat/zlib/zconf.h [new file with mode: 0644]
deps/libretro-common/include/compat/zlib/zconf.h.in [new file with mode: 0644]
deps/libretro-common/include/compat/zlib/zlib.h [new file with mode: 0644]
deps/libretro-common/include/compat/zlib/zutil.h [new file with mode: 0644]
deps/libretro-common/include/compat/zutil.h [new file with mode: 0644]
deps/libretro-common/include/defines/cocoa_defines.h [new file with mode: 0644]
deps/libretro-common/include/defines/d3d_defines.h [new file with mode: 0644]
deps/libretro-common/include/defines/gx_defines.h [new file with mode: 0644]
deps/libretro-common/include/defines/ps3_defines.h [new file with mode: 0644]
deps/libretro-common/include/defines/ps4_defines.h [new file with mode: 0644]
deps/libretro-common/include/defines/psp_defines.h [new file with mode: 0644]
deps/libretro-common/include/dynamic/dylib.h [new file with mode: 0644]
deps/libretro-common/include/encodings/base64.h [new file with mode: 0644]
deps/libretro-common/include/encodings/crc32.h [new file with mode: 0644]
deps/libretro-common/include/encodings/utf.h [new file with mode: 0644]
deps/libretro-common/include/encodings/win32.h [new file with mode: 0644]
deps/libretro-common/include/fastcpy.h [new file with mode: 0644]
deps/libretro-common/include/features/features_cpu.h [new file with mode: 0644]
deps/libretro-common/include/file/archive_file.h [new file with mode: 0644]
deps/libretro-common/include/file/config_file.h [new file with mode: 0644]
deps/libretro-common/include/file/config_file_userdata.h [new file with mode: 0644]
deps/libretro-common/include/file/file_path.h [new file with mode: 0644]
deps/libretro-common/include/file/nbio.h [new file with mode: 0644]
deps/libretro-common/include/filters.h [new file with mode: 0644]
deps/libretro-common/include/formats/cdfs.h [new file with mode: 0644]
deps/libretro-common/include/formats/image.h [new file with mode: 0644]
deps/libretro-common/include/formats/logiqx_dat.h [new file with mode: 0644]
deps/libretro-common/include/formats/m3u_file.h [new file with mode: 0644]
deps/libretro-common/include/formats/rbmp.h [new file with mode: 0644]
deps/libretro-common/include/formats/rjpeg.h [new file with mode: 0644]
deps/libretro-common/include/formats/rjson.h [new file with mode: 0644]
deps/libretro-common/include/formats/rjson_helpers.h [new file with mode: 0644]
deps/libretro-common/include/formats/rpng.h [new file with mode: 0644]
deps/libretro-common/include/formats/rtga.h [new file with mode: 0644]
deps/libretro-common/include/formats/rwav.h [new file with mode: 0644]
deps/libretro-common/include/formats/rxml.h [new file with mode: 0644]
deps/libretro-common/include/gfx/gl_capabilities.h [new file with mode: 0644]
deps/libretro-common/include/gfx/math/matrix_3x3.h [new file with mode: 0644]
deps/libretro-common/include/gfx/math/matrix_4x4.h [new file with mode: 0644]
deps/libretro-common/include/gfx/math/vector_2.h [new file with mode: 0644]
deps/libretro-common/include/gfx/math/vector_3.h [new file with mode: 0644]
deps/libretro-common/include/gfx/math/vector_4.h [new file with mode: 0644]
deps/libretro-common/include/gfx/scaler/filter.h [new file with mode: 0644]
deps/libretro-common/include/gfx/scaler/pixconv.h [new file with mode: 0644]
deps/libretro-common/include/gfx/scaler/scaler.h [new file with mode: 0644]
deps/libretro-common/include/gfx/scaler/scaler_int.h [new file with mode: 0644]
deps/libretro-common/include/gfx/video_frame.h [new file with mode: 0644]
deps/libretro-common/include/glsm/glsm.h [new file with mode: 0644]
deps/libretro-common/include/glsm/glsmsym.h [new file with mode: 0644]
deps/libretro-common/include/glsym/glsym.h [new file with mode: 0644]
deps/libretro-common/include/glsym/glsym_es2.h [new file with mode: 0644]
deps/libretro-common/include/glsym/glsym_es3.h [new file with mode: 0644]
deps/libretro-common/include/glsym/glsym_gl.h [new file with mode: 0644]
deps/libretro-common/include/glsym/rglgen.h [new file with mode: 0644]
deps/libretro-common/include/glsym/rglgen_headers.h [new file with mode: 0644]
deps/libretro-common/include/glsym/rglgen_private_headers.h [new file with mode: 0644]
deps/libretro-common/include/glsym/switch/nx_gl.h [new file with mode: 0644]
deps/libretro-common/include/glsym/switch/nx_glsym.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/bitstream.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/cdrom.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/chd.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/coretypes.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/flac.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/huffman.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/libchdr_zlib.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/lzma.h [new file with mode: 0644]
deps/libretro-common/include/libchdr/minmax.h [new file with mode: 0644]
deps/libretro-common/include/libco.h [new file with mode: 0644]
deps/libretro-common/include/libretro.h [new file with mode: 0644]
deps/libretro-common/include/libretro_d3d.h [new file with mode: 0644]
deps/libretro-common/include/libretro_dspfilter.h [new file with mode: 0644]
deps/libretro-common/include/libretro_gskit_ps2.h [new file with mode: 0644]
deps/libretro-common/include/libretro_vulkan.h [new file with mode: 0644]
deps/libretro-common/include/lists/dir_list.h [new file with mode: 0644]
deps/libretro-common/include/lists/file_list.h [new file with mode: 0644]
deps/libretro-common/include/lists/linked_list.h [new file with mode: 0644]
deps/libretro-common/include/lists/nested_list.h [new file with mode: 0644]
deps/libretro-common/include/lists/string_list.h [new file with mode: 0644]
deps/libretro-common/include/lrc_hash.h [new file with mode: 0644]
deps/libretro-common/include/math/complex.h [new file with mode: 0644]
deps/libretro-common/include/math/float_minmax.h [new file with mode: 0644]
deps/libretro-common/include/math/fxp.h [new file with mode: 0644]
deps/libretro-common/include/media/media_detect_cd.h [new file with mode: 0644]
deps/libretro-common/include/memalign.h [new file with mode: 0644]
deps/libretro-common/include/memmap.h [new file with mode: 0644]
deps/libretro-common/include/net/net_compat.h [new file with mode: 0644]
deps/libretro-common/include/net/net_http.h [new file with mode: 0644]
deps/libretro-common/include/net/net_http_parse.h [new file with mode: 0644]
deps/libretro-common/include/net/net_ifinfo.h [new file with mode: 0644]
deps/libretro-common/include/net/net_socket.h [new file with mode: 0644]
deps/libretro-common/include/net/net_socket_ssl.h [new file with mode: 0644]
deps/libretro-common/include/playlists/label_sanitization.h [new file with mode: 0644]
deps/libretro-common/include/queues/fifo_queue.h [new file with mode: 0644]
deps/libretro-common/include/queues/generic_queue.h [new file with mode: 0644]
deps/libretro-common/include/queues/message_queue.h [new file with mode: 0644]
deps/libretro-common/include/queues/task_queue.h [new file with mode: 0644]
deps/libretro-common/include/retro_assert.h [new file with mode: 0644]
deps/libretro-common/include/retro_common.h [new file with mode: 0644]
deps/libretro-common/include/retro_common_api.h [new file with mode: 0644]
deps/libretro-common/include/retro_dirent.h [new file with mode: 0644]
deps/libretro-common/include/retro_endianness.h [new file with mode: 0644]
deps/libretro-common/include/retro_environment.h [new file with mode: 0644]
deps/libretro-common/include/retro_inline.h [new file with mode: 0644]
deps/libretro-common/include/retro_math.h [new file with mode: 0644]
deps/libretro-common/include/retro_miscellaneous.h [new file with mode: 0644]
deps/libretro-common/include/retro_stat.h [new file with mode: 0644]
deps/libretro-common/include/retro_timers.h [new file with mode: 0644]
deps/libretro-common/include/rthreads/async_job.h [new file with mode: 0644]
deps/libretro-common/include/rthreads/rthreads.h [new file with mode: 0644]
deps/libretro-common/include/rthreads/tpool.h [new file with mode: 0644]
deps/libretro-common/include/streams/chd_stream.h [new file with mode: 0644]
deps/libretro-common/include/streams/file_stream.h [new file with mode: 0644]
deps/libretro-common/include/streams/file_stream_transforms.h [new file with mode: 0644]
deps/libretro-common/include/streams/interface_stream.h [new file with mode: 0644]
deps/libretro-common/include/streams/memory_stream.h [new file with mode: 0644]
deps/libretro-common/include/streams/network_stream.h [new file with mode: 0644]
deps/libretro-common/include/streams/rzip_stream.h [new file with mode: 0644]
deps/libretro-common/include/streams/stdin_stream.h [new file with mode: 0644]
deps/libretro-common/include/streams/trans_stream.h [new file with mode: 0644]
deps/libretro-common/include/string/stdstring.h [new file with mode: 0644]
deps/libretro-common/include/time/rtime.h [new file with mode: 0644]
deps/libretro-common/include/utils/md5.h [new file with mode: 0644]
deps/libretro-common/include/vfs/vfs.h [new file with mode: 0644]
deps/libretro-common/include/vfs/vfs_implementation.h [new file with mode: 0644]
deps/libretro-common/include/vfs/vfs_implementation_cdrom.h [new file with mode: 0644]
deps/libretro-common/include/vulkan/vulkan_symbol_wrapper.h [new file with mode: 0644]
deps/libretro-common/libco/aarch64.c [new file with mode: 0644]
deps/libretro-common/libco/amd64.c [new file with mode: 0644]
deps/libretro-common/libco/armeabi.c [new file with mode: 0644]
deps/libretro-common/libco/fiber.c [new file with mode: 0644]
deps/libretro-common/libco/genode.cpp [new file with mode: 0644]
deps/libretro-common/libco/libco.c [new file with mode: 0644]
deps/libretro-common/libco/ppc.c [new file with mode: 0644]
deps/libretro-common/libco/ps2.c [new file with mode: 0644]
deps/libretro-common/libco/ps3.S [new file with mode: 0644]
deps/libretro-common/libco/psp1.c [new file with mode: 0644]
deps/libretro-common/libco/psp2.c [new file with mode: 0644]
deps/libretro-common/libco/scefiber.c [new file with mode: 0644]
deps/libretro-common/libco/sjlj.c [new file with mode: 0644]
deps/libretro-common/libco/ucontext.c [new file with mode: 0644]
deps/libretro-common/libco/x86.c [new file with mode: 0644]
deps/libretro-common/lists/dir_list.c [new file with mode: 0644]
deps/libretro-common/lists/file_list.c [new file with mode: 0644]
deps/libretro-common/lists/linked_list.c [new file with mode: 0644]
deps/libretro-common/lists/nested_list.c [new file with mode: 0644]
deps/libretro-common/lists/string_list.c [new file with mode: 0644]
deps/libretro-common/lists/vector_list.c [new file with mode: 0644]
deps/libretro-common/media/media_detect_cd.c [new file with mode: 0644]
deps/libretro-common/memmap/memalign.c [new file with mode: 0644]
deps/libretro-common/memmap/memmap.c [new file with mode: 0644]
deps/libretro-common/net/net_compat.c [new file with mode: 0644]
deps/libretro-common/net/net_http.c [new file with mode: 0644]
deps/libretro-common/net/net_http_parse.c [new file with mode: 0644]
deps/libretro-common/net/net_ifinfo.c [new file with mode: 0644]
deps/libretro-common/net/net_socket.c [new file with mode: 0644]
deps/libretro-common/net/net_socket_ssl_bear.c [new file with mode: 0644]
deps/libretro-common/net/net_socket_ssl_mbed.c [new file with mode: 0644]
deps/libretro-common/playlists/label_sanitization.c [new file with mode: 0644]
deps/libretro-common/queues/fifo_queue.c [new file with mode: 0644]
deps/libretro-common/queues/generic_queue.c [new file with mode: 0644]
deps/libretro-common/queues/message_queue.c [new file with mode: 0644]
deps/libretro-common/queues/task_queue.c [new file with mode: 0644]
deps/libretro-common/rthreads/ctr_pthread.h [new file with mode: 0644]
deps/libretro-common/rthreads/gx_pthread.h [new file with mode: 0644]
deps/libretro-common/rthreads/psp_pthread.h [new file with mode: 0644]
deps/libretro-common/rthreads/rthreads.c [new file with mode: 0644]
deps/libretro-common/rthreads/tpool.c [new file with mode: 0644]
deps/libretro-common/rthreads/wiiu_pthread.h [new file with mode: 0644]
deps/libretro-common/rthreads/xenon_sdl_threads.c [new file with mode: 0644]
deps/libretro-common/samples/compat/fnmatch/Makefile [new file with mode: 0644]
deps/libretro-common/samples/compat/fnmatch/compat_fnmatch_test.c [new file with mode: 0644]
deps/libretro-common/samples/compat/snprintf/Makefile [new file with mode: 0644]
deps/libretro-common/samples/compat/snprintf/snprintf_test.c [new file with mode: 0644]
deps/libretro-common/samples/compat/strl/Makefile [new file with mode: 0644]
deps/libretro-common/samples/compat/strl/strl_test.c [new file with mode: 0644]
deps/libretro-common/samples/core_options/README.md [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_categories/conversion_scripts/core_option_regex.py [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_categories/conversion_scripts/v1_to_v2_converter.py [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_categories/libretro_core_options.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_categories/libretro_core_options_intl.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_default/libretro_core_options.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/libretro_core_options.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_intl.yml [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_prep.yml [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/crowdin.yml [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/instructions.txt [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/.gitignore [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_opt_translation.py [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_option_regex.py [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_intl.py [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_prep.py [new file with mode: 0644]
deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/v1_to_v2_converter.py [new file with mode: 0644]
deps/libretro-common/samples/file/config_file/Makefile [new file with mode: 0644]
deps/libretro-common/samples/file/config_file/config_file_test.c [new file with mode: 0644]
deps/libretro-common/samples/file/nbio/Makefile [new file with mode: 0644]
deps/libretro-common/samples/file/nbio/nbio_test.c [new file with mode: 0644]
deps/libretro-common/samples/formats/png/Makefile [new file with mode: 0644]
deps/libretro-common/samples/formats/png/rpng_test.c [new file with mode: 0644]
deps/libretro-common/samples/formats/xml/Makefile [new file with mode: 0644]
deps/libretro-common/samples/formats/xml/rxml_test.c [new file with mode: 0644]
deps/libretro-common/samples/net/Makefile [new file with mode: 0644]
deps/libretro-common/samples/net/http_test [new file with mode: 0644]
deps/libretro-common/samples/net/net_http_parse_test.c [new file with mode: 0644]
deps/libretro-common/samples/net/net_http_test.c [new file with mode: 0644]
deps/libretro-common/samples/net/net_ifinfo [new file with mode: 0644]
deps/libretro-common/samples/net/net_ifinfo_test.c [new file with mode: 0644]
deps/libretro-common/samples/net/udp-test.c [new file with mode: 0644]
deps/libretro-common/samples/streams/rzip/Makefile [new file with mode: 0644]
deps/libretro-common/samples/streams/rzip/rzip.c [new file with mode: 0644]
deps/libretro-common/samples/utils/Makefile [new file with mode: 0644]
deps/libretro-common/samples/utils/crc32.c [new file with mode: 0644]
deps/libretro-common/samples/utils/md5_test.c [new file with mode: 0644]
deps/libretro-common/samples/utils/sha1_main.c [new file with mode: 0644]
deps/libretro-common/streams/chd_stream.c [new file with mode: 0644]
deps/libretro-common/streams/file_stream.c [new file with mode: 0644]
deps/libretro-common/streams/file_stream_transforms.c [new file with mode: 0644]
deps/libretro-common/streams/interface_stream.c [new file with mode: 0644]
deps/libretro-common/streams/memory_stream.c [new file with mode: 0644]
deps/libretro-common/streams/network_stream.c [new file with mode: 0644]
deps/libretro-common/streams/rzip_stream.c [new file with mode: 0644]
deps/libretro-common/streams/stdin_stream.c [new file with mode: 0644]
deps/libretro-common/streams/trans_stream.c [new file with mode: 0644]
deps/libretro-common/streams/trans_stream_pipe.c [new file with mode: 0644]
deps/libretro-common/streams/trans_stream_zlib.c [new file with mode: 0644]
deps/libretro-common/string/stdstring.c [new file with mode: 0644]
deps/libretro-common/test/hash/test_hash.c [new file with mode: 0644]
deps/libretro-common/test/lists/test_linked_list.c [new file with mode: 0644]
deps/libretro-common/test/queues/test_generic_queue.c [new file with mode: 0644]
deps/libretro-common/test/string/test_stdstring.c [new file with mode: 0644]
deps/libretro-common/test/utils/test_utils.c [new file with mode: 0644]
deps/libretro-common/time/rtime.c [new file with mode: 0644]
deps/libretro-common/utils/debugbreak/debugbreak.c [new file with mode: 0644]
deps/libretro-common/utils/djb2.c [new file with mode: 0644]
deps/libretro-common/utils/md5.c [new file with mode: 0644]
deps/libretro-common/utils/sha1.c [new file with mode: 0644]
deps/libretro-common/vfs/vfs_implementation.c [new file with mode: 0644]
deps/libretro-common/vfs/vfs_implementation_cdrom.c [new file with mode: 0644]
deps/libretro-common/vfs/vfs_implementation_uwp.cpp [new file with mode: 0644]
deps/libretro-common/vulkan/vulkan_symbol_wrapper.c [new file with mode: 0644]

diff --git a/deps/libretro-common/.gitignore b/deps/libretro-common/.gitignore
new file mode 100644 (file)
index 0000000..4e88cc3
--- /dev/null
@@ -0,0 +1,6 @@
+glsm/
+*.[od]
+*.dll
+*.so
+*.dylib
+*.exe
diff --git a/deps/libretro-common/.gitrepo b/deps/libretro-common/.gitrepo
new file mode 100644 (file)
index 0000000..a853644
--- /dev/null
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+       remote = https://github.com/libretro/libretro-common.git
+       branch = master
+       commit = 86d5e4128c072255c123d535cae97789023ee54b
+       parent = 95bc7ce4ee8d7d3c9de934d61d3200ec4d99390d
+       method = merge
+       cmdver = 0.4.3
diff --git a/deps/libretro-common/Makefile.test b/deps/libretro-common/Makefile.test
new file mode 100644 (file)
index 0000000..4e1deed
--- /dev/null
@@ -0,0 +1,58 @@
+
+OBJDIR = ../obj-unix
+
+TEST_UNIT_CFLAGS = $(CFLAGS) -Iinclude $(LDFLAGS) -lcheck $(LIBCHECK_CFLAGS) -Werror -Wdeclaration-after-statement -fsanitize=address -fsanitize=undefined -ftest-coverage -fprofile-arcs -ggdb
+
+TEST_GENERIC_QUEUE = test/queues/test_generic_queue
+TEST_GENERIC_QUEUE_SRC = test/queues/test_generic_queue.c queues/generic_queue.c
+
+TEST_LINKED_LIST = test/lists/test_linked_list
+TEST_LINKED_LIST_SRC = test/lists/test_linked_list.c lists/linked_list.c
+
+TEST_STDSTRING = test/string/test_stdstring
+TEST_STDSTRING_SRC = test/string/test_stdstring.c string/stdstring.c encodings/encoding_utf.c \
+                    compat/compat_strl.c
+
+TEST_UTILS = test/utils/test_utils
+TEST_UTILS_SRC = test/utils/test_utils.c utils/md5.c encodings/encoding_crc32.c \
+               streams/file_stream.c vfs/vfs_implementation.c file/file_path.c \
+               compat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c
+
+TEST_HASH = test/hash/test_hash
+TEST_HASH_SRC = test/hash/test_hash.c hash/lrc_hash.c \
+               streams/file_stream.c vfs/vfs_implementation.c file/file_path.c \
+               compat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c
+
+all:
+       # Build and execute tests in order, to avoid coverage file collision
+       # string
+       $(CC) $(TEST_UNIT_CFLAGS) $(TEST_STDSTRING_SRC) -o $(TEST_STDSTRING)
+       $(TEST_STDSTRING)
+       lcov -c -d . -o `dirname $(TEST_STDSTRING)`/coverage.info
+       # utils
+       $(CC) $(TEST_UNIT_CFLAGS) $(TEST_UTILS_SRC) -o $(TEST_UTILS)
+       $(TEST_UTILS)
+       lcov -c -d . -o `dirname $(TEST_UTILS)`/coverage.info
+       # utils
+       $(CC) $(TEST_UNIT_CFLAGS) $(TEST_HASH_SRC) -o $(TEST_HASH)
+       $(TEST_HASH)
+       lcov -c -d . -o `dirname $(TEST_HASH)`/coverage.info
+       # list
+       $(CC) $(TEST_UNIT_CFLAGS) $(TEST_LINKED_LIST_SRC) -o $(TEST_LINKED_LIST)
+       $(TEST_LINKED_LIST)
+       lcov -c -d . -o `dirname $(TEST_LINKED_LIST)`/coverage.info
+       # queue
+       $(CC) $(TEST_UNIT_CFLAGS) $(TEST_GENERIC_QUEUE_SRC) -o $(TEST_GENERIC_QUEUE)
+       $(TEST_GENERIC_QUEUE)
+       lcov -c -d . -o `dirname $(TEST_GENERIC_QUEUE)`/coverage.info
+       
+       lcov -o test/coverage.info \
+            -a test/utils/coverage.info \
+            -a test/string/coverage.info \
+            -a test/lists/coverage.info \
+            -a test/queues/coverage.info
+       genhtml -o test/coverage/ test/coverage.info
+
+clean:
+       rm -f *.gcda *.gcno
+
diff --git a/deps/libretro-common/audio/audio_mix.c b/deps/libretro-common/audio/audio_mix.c
new file mode 100644 (file)
index 0000000..eb138ed
--- /dev/null
@@ -0,0 +1,377 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (audio_mix.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <memalign.h>
+
+#include <retro_environment.h>
+
+#if defined(__SSE2__)
+#include <emmintrin.h>
+#elif defined(__ALTIVEC__)
+#include <altivec.h>
+#endif
+
+#include <retro_miscellaneous.h>
+#include <audio/audio_mix.h>
+#include <streams/file_stream.h>
+#include <audio/conversion/float_to_s16.h>
+#include <audio/conversion/s16_to_float.h>
+
+void audio_mix_volume_C(float *out, const float *in, float vol, size_t samples)
+{
+   size_t i;
+   for (i = 0; i < samples; i++)
+      out[i] += in[i] * vol;
+}
+
+#ifdef __SSE2__
+void audio_mix_volume_SSE2(float *out, const float *in, float vol, size_t samples)
+{
+   size_t i, remaining_samples;
+   __m128 volume = _mm_set1_ps(vol);
+
+   for (i = 0; i + 16 <= samples; i += 16, out += 16, in += 16)
+   {
+      unsigned j;
+      __m128 input[4];
+      __m128 additive[4];
+
+      input[0]    = _mm_loadu_ps(out +  0);
+      input[1]    = _mm_loadu_ps(out +  4);
+      input[2]    = _mm_loadu_ps(out +  8);
+      input[3]    = _mm_loadu_ps(out + 12);
+
+      additive[0] = _mm_mul_ps(volume, _mm_loadu_ps(in +  0));
+      additive[1] = _mm_mul_ps(volume, _mm_loadu_ps(in +  4));
+      additive[2] = _mm_mul_ps(volume, _mm_loadu_ps(in +  8));
+      additive[3] = _mm_mul_ps(volume, _mm_loadu_ps(in + 12));
+
+      for (j = 0; j < 4; j++)
+         _mm_storeu_ps(out + 4 * j, _mm_add_ps(input[j], additive[j]));
+   }
+
+   remaining_samples = samples - i;
+
+   for (i = 0; i < remaining_samples; i++)
+      out[i] += in[i] * vol;
+}
+#endif
+
+void audio_mix_free_chunk(audio_chunk_t *chunk)
+{
+   if (!chunk)
+      return;
+
+#ifdef HAVE_RWAV
+   if (chunk->rwav && chunk->rwav->samples)
+   {
+      /* rwav_free only frees the samples */
+      rwav_free(chunk->rwav);
+      free(chunk->rwav);
+   }
+#endif
+
+   if (chunk->buf)
+      free(chunk->buf);
+
+   if (chunk->upsample_buf)
+      memalign_free(chunk->upsample_buf);
+
+   if (chunk->float_buf)
+      memalign_free(chunk->float_buf);
+
+   if (chunk->float_resample_buf)
+      memalign_free(chunk->float_resample_buf);
+
+   if (chunk->resample_buf)
+      memalign_free(chunk->resample_buf);
+
+   if (chunk->resampler && chunk->resampler_data)
+      chunk->resampler->free(chunk->resampler_data);
+
+   free(chunk);
+}
+
+audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,
+      const char *resampler_ident, enum resampler_quality quality)
+{
+#ifdef HAVE_RWAV
+   int sample_size;
+   int64_t len                = 0;
+   void *buf                  = NULL;
+   audio_chunk_t *chunk       = (audio_chunk_t*)malloc(sizeof(*chunk));
+
+   if (!chunk)
+      return NULL;
+
+   chunk->buf                 = NULL;
+   chunk->upsample_buf        = NULL;
+   chunk->float_buf           = NULL;
+   chunk->float_resample_buf  = NULL;
+   chunk->resample_buf        = NULL;
+   chunk->len                 = 0;
+   chunk->resample_len        = 0;
+   chunk->sample_rate         = sample_rate;
+   chunk->resample            = false;
+   chunk->resampler           = NULL;
+   chunk->resampler_data      = NULL;
+   chunk->ratio               = 0.00f;
+   chunk->rwav                = (rwav_t*)malloc(sizeof(rwav_t));
+
+   if (!chunk->rwav)
+      goto error;
+
+   chunk->rwav->bitspersample = 0;
+   chunk->rwav->numchannels   = 0;
+   chunk->rwav->samplerate    = 0;
+   chunk->rwav->numsamples    = 0;
+   chunk->rwav->subchunk2size = 0;
+   chunk->rwav->samples       = NULL;
+
+   if (!filestream_read_file(path, &buf, &len))
+      goto error;
+
+   chunk->buf                 = buf;
+   chunk->len                 = len;
+
+   if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR)
+      goto error;
+
+   /* numsamples does not know or care about
+    * multiple channels, but we need space for 2 */
+   chunk->upsample_buf        = (int16_t*)memalign_alloc(128,
+         chunk->rwav->numsamples * 2 * sizeof(int16_t));
+
+   sample_size                = chunk->rwav->bitspersample / 8;
+
+   if (sample_size == 1)
+   {
+      unsigned i;
+
+      if (chunk->rwav->numchannels == 1)
+      {
+         for (i = 0; i < chunk->rwav->numsamples; i++)
+         {
+            uint8_t *sample                  = (
+                  (uint8_t*)chunk->rwav->samples) + i;
+
+            chunk->upsample_buf[i * 2]       = 
+               (int16_t)((sample[0] - 128) << 8);
+            chunk->upsample_buf[(i * 2) + 1] = 
+               (int16_t)((sample[0] - 128) << 8);
+         }
+      }
+      else if (chunk->rwav->numchannels == 2)
+      {
+         for (i = 0; i < chunk->rwav->numsamples; i++)
+         {
+            uint8_t *sample                  = (
+                  (uint8_t*)chunk->rwav->samples) +
+               (i * 2);
+
+            chunk->upsample_buf[i * 2]       = 
+               (int16_t)((sample[0] - 128) << 8);
+            chunk->upsample_buf[(i * 2) + 1] = 
+               (int16_t)((sample[1] - 128) << 8);
+         }
+      }
+   }
+   else if (sample_size == 2)
+   {
+      if (chunk->rwav->numchannels == 1)
+      {
+         unsigned i;
+
+         for (i = 0; i < chunk->rwav->numsamples; i++)
+         {
+            int16_t sample                   = ((int16_t*)
+                  chunk->rwav->samples)[i];
+
+            chunk->upsample_buf[i * 2]       = sample;
+            chunk->upsample_buf[(i * 2) + 1] = sample;
+         }
+      }
+      else if (chunk->rwav->numchannels == 2)
+         memcpy(chunk->upsample_buf, chunk->rwav->samples,
+               chunk->rwav->subchunk2size);
+   }
+   else if (sample_size != 2)
+   {
+      /* we don't support any other sample size besides 8 and 16-bit yet */
+      goto error;
+   }
+
+   if (sample_rate != (int)chunk->rwav->samplerate)
+   {
+      chunk->resample = true;
+      chunk->ratio    = (double)sample_rate / chunk->rwav->samplerate;
+
+      retro_resampler_realloc(&chunk->resampler_data,
+            &chunk->resampler,
+            resampler_ident,
+            quality,
+            chunk->ratio);
+
+      if (chunk->resampler && chunk->resampler_data)
+      {
+         struct resampler_data info;
+
+         chunk->float_buf          = (float*)memalign_alloc(128,
+               chunk->rwav->numsamples * 2 * 
+               chunk->ratio * sizeof(float));
+
+         /* why is *3 needed instead of just *2? Does the 
+          * sinc driver require more space than we know about? */
+         chunk->float_resample_buf = (float*)memalign_alloc(128,
+               chunk->rwav->numsamples * 3 * 
+               chunk->ratio * sizeof(float));
+
+         convert_s16_to_float(chunk->float_buf,
+               chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0);
+
+         info.data_in       = (const float*)chunk->float_buf;
+         info.data_out      = chunk->float_resample_buf;
+         /* a 'frame' consists of two channels, so we set this
+          * to the number of samples irrespective of channel count */
+         info.input_frames  = chunk->rwav->numsamples;
+         info.output_frames = 0;
+         info.ratio         = chunk->ratio;
+
+         chunk->resampler->process(chunk->resampler_data, &info);
+
+         /* number of output_frames does not increase with 
+          * multiple channels, but assume we need space for 2 */
+         chunk->resample_buf = (int16_t*)memalign_alloc(128,
+               info.output_frames * 2 * sizeof(int16_t));
+         chunk->resample_len = info.output_frames;
+         convert_float_to_s16(chunk->resample_buf,
+               chunk->float_resample_buf, info.output_frames * 2);
+      }
+   }
+
+   return chunk;
+
+error:
+   audio_mix_free_chunk(chunk);
+#endif
+   return NULL;
+}
+
+size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)
+{
+   if (!chunk)
+      return 0;
+
+#ifdef HAVE_RWAV
+   if (chunk->rwav)
+   {
+      if (chunk->resample)
+         return chunk->resample_len;
+      return chunk->rwav->numsamples;
+   }
+#endif
+
+   /* no other filetypes supported yet */
+   return 0;
+}
+
+/**
+ * audio_mix_get_chunk_sample:
+ * @chunk              : audio chunk instance
+ * @channel            : channel of the sample (0=left, 1=right)
+ * @index              : index of the sample
+ *
+ * Get a sample from an audio chunk.
+ *
+ * Returns: A signed 16-bit audio sample.
+ **/
+int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk,
+      unsigned channel, size_t index)
+{
+   if (!chunk)
+      return 0;
+
+#ifdef HAVE_RWAV
+   if (chunk->rwav)
+   {
+      int sample_size    = chunk->rwav->bitspersample / 8;
+      int16_t sample_out = 0;
+
+      /* 0 is the first/left channel */
+      uint8_t *sample    = NULL;
+
+      if (chunk->resample)
+         sample = (uint8_t*)chunk->resample_buf +
+            (sample_size * index * chunk->rwav->numchannels) 
+            + (channel * sample_size);
+      else
+         sample = (uint8_t*)chunk->upsample_buf +
+            (sample_size * index * chunk->rwav->numchannels) 
+            + (channel * sample_size);
+
+      sample_out = (int16_t)*sample;
+
+      return sample_out;
+   }
+#endif
+
+   /* no other filetypes supported yet */
+   return 0;
+}
+
+int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)
+{
+   if (!chunk)
+      return 0;
+
+#ifdef HAVE_RWAV
+   if (chunk->rwav)
+   {
+      int16_t *sample;
+
+      if (chunk->resample)
+         sample = chunk->resample_buf;
+      else
+         sample = chunk->upsample_buf;
+
+      return sample;
+   }
+#endif
+
+   return NULL;
+}
+
+int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk)
+{
+   if (!chunk)
+      return 0;
+
+#ifdef HAVE_RWAV
+   if (chunk->rwav)
+      return chunk->rwav->numchannels;
+#endif
+
+   /* don't support other formats yet */
+   return 0;
+}
diff --git a/deps/libretro-common/audio/audio_mixer.c b/deps/libretro-common/audio/audio_mixer.c
new file mode 100644 (file)
index 0000000..a274989
--- /dev/null
@@ -0,0 +1,1400 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (audio_mixer.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#include <audio/audio_mixer.h>
+#include <audio/audio_resampler.h>
+
+#ifdef HAVE_RWAV
+#include <formats/rwav.h>
+#endif
+#include <memalign.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_STB_VORBIS
+#define STB_VORBIS_NO_PUSHDATA_API
+#define STB_VORBIS_NO_STDIO
+#define STB_VORBIS_NO_CRT
+
+#include <stb/stb_vorbis.h>
+#endif
+
+#ifdef HAVE_DR_FLAC
+#define DR_FLAC_IMPLEMENTATION
+#include <dr/dr_flac.h>
+#endif
+
+#ifdef HAVE_DR_MP3
+#define DR_MP3_IMPLEMENTATION
+#include <retro_assert.h>
+#define DRMP3_ASSERT(expression) retro_assert(expression)
+#include <dr/dr_mp3.h>
+#endif
+
+#ifdef HAVE_IBXM
+#include <ibxm/ibxm.h>
+#endif
+
+#ifdef HAVE_THREADS
+#include <rthreads/rthreads.h>
+#define AUDIO_MIXER_LOCK(voice)   slock_lock(voice->lock)
+#define AUDIO_MIXER_UNLOCK(voice) slock_unlock(voice->lock)
+#else
+#define AUDIO_MIXER_LOCK(voice)   do {} while(0)
+#define AUDIO_MIXER_UNLOCK(voice) do {} while(0)
+#endif
+
+#define AUDIO_MIXER_MAX_VOICES      8
+#define AUDIO_MIXER_TEMP_BUFFER 8192
+
+struct audio_mixer_sound
+{
+   enum audio_mixer_type type;
+
+   union
+   {
+      struct
+      {
+         /* wav */
+         const float* pcm;
+         unsigned frames;
+      } wav;
+
+#ifdef HAVE_STB_VORBIS
+      struct
+      {
+         /* ogg */
+         const void* data;
+         unsigned size;
+      } ogg;
+#endif
+
+#ifdef HAVE_DR_FLAC
+      struct
+      {
+          /* flac */
+         const void* data;
+         unsigned size;
+      } flac;
+#endif
+
+#ifdef HAVE_DR_MP3
+      struct
+      {
+          /* mp */
+         const void* data;
+         unsigned size;
+      } mp3;
+#endif
+
+#ifdef HAVE_IBXM
+      struct
+      {
+         /* mod/s3m/xm */
+         const void* data;
+         unsigned size;
+      } mod;
+#endif
+   } types;
+};
+
+struct audio_mixer_voice
+{
+   struct
+   {
+      struct
+      {
+         unsigned position;
+      } wav;
+
+#ifdef HAVE_STB_VORBIS
+      struct
+      {
+         stb_vorbis *stream;
+         void       *resampler_data;
+         const retro_resampler_t *resampler;
+         float      *buffer;
+         unsigned    position;
+         unsigned    samples;
+         unsigned    buf_samples;
+         float       ratio;
+      } ogg;
+#endif
+
+#ifdef HAVE_DR_FLAC
+      struct
+      {
+         float*      buffer;
+         drflac      *stream;
+         void        *resampler_data;
+         const retro_resampler_t *resampler;
+         unsigned    position;
+         unsigned    samples;
+         unsigned    buf_samples;
+         float       ratio;
+      } flac;
+#endif
+
+#ifdef HAVE_DR_MP3
+      struct
+      {
+         drmp3       stream;
+         void        *resampler_data;
+         const retro_resampler_t *resampler;
+         float*      buffer;
+         unsigned    position;
+         unsigned    samples;
+         unsigned    buf_samples;
+         float       ratio;
+      } mp3;
+#endif
+
+#ifdef HAVE_IBXM
+      struct
+      {
+         int*              buffer;
+         struct replay*    stream;
+         struct module*    module;
+         unsigned          position;
+         unsigned          samples;
+         unsigned          buf_samples;
+      } mod;
+#endif
+   } types;
+   audio_mixer_sound_t *sound;
+   audio_mixer_stop_cb_t stop_cb;
+   unsigned type;
+   float    volume;
+   bool     repeat;
+#ifdef HAVE_THREADS
+   slock_t *lock;
+#endif
+};
+
+/* TODO/FIXME - static globals */
+static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0};
+static unsigned s_rate = 0;
+
+static void audio_mixer_release(audio_mixer_voice_t* voice);
+
+#ifdef HAVE_RWAV
+static bool wav_to_float(const rwav_t* wav, float** pcm, size_t samples_out)
+{
+   size_t i;
+   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
+   float *f           = (float*)memalign_alloc(16,
+         ((samples_out + 15) & ~15) * sizeof(float));
+
+   if (!f)
+      return false;
+
+   *pcm = f;
+
+   if (wav->bitspersample == 8)
+   {
+      float sample      = 0.0f;
+      const uint8_t *u8 = (const uint8_t*)wav->samples;
+
+      if (wav->numchannels == 1)
+      {
+         for (i = wav->numsamples; i != 0; i--)
+         {
+            sample = (float)*u8++ / 255.0f;
+            sample = sample * 2.0f - 1.0f;
+            *f++   = sample;
+            *f++   = sample;
+         }
+      }
+      else if (wav->numchannels == 2)
+      {
+         for (i = wav->numsamples; i != 0; i--)
+         {
+            sample = (float)*u8++ / 255.0f;
+            sample = sample * 2.0f - 1.0f;
+            *f++   = sample;
+            sample = (float)*u8++ / 255.0f;
+            sample = sample * 2.0f - 1.0f;
+            *f++   = sample;
+         }
+      }
+   }
+   else
+   {
+      /* TODO/FIXME note to leiradel - can we use audio/conversion/s16_to_float
+       * functions here? */
+
+      float sample       = 0.0f;
+      const int16_t *s16 = (const int16_t*)wav->samples;
+
+      if (wav->numchannels == 1)
+      {
+         for (i = wav->numsamples; i != 0; i--)
+         {
+            sample = (float)((int)*s16++ + 32768) / 65535.0f;
+            sample = sample * 2.0f - 1.0f;
+            *f++   = sample;
+            *f++   = sample;
+         }
+      }
+      else if (wav->numchannels == 2)
+      {
+         for (i = wav->numsamples; i != 0; i--)
+         {
+            sample = (float)((int)*s16++ + 32768) / 65535.0f;
+            sample = sample * 2.0f - 1.0f;
+            *f++   = sample;
+            sample = (float)((int)*s16++ + 32768) / 65535.0f;
+            sample = sample * 2.0f - 1.0f;
+            *f++   = sample;
+         }
+      }
+   }
+
+   return true;
+}
+
+static bool one_shot_resample(const float* in, size_t samples_in,
+      unsigned rate, const char *resampler_ident, enum resampler_quality quality,
+      float** out, size_t* samples_out)
+{
+   struct resampler_data info;
+   void* data                         = NULL;
+   const retro_resampler_t* resampler = NULL;
+   float ratio                        = (double)s_rate / (double)rate;
+
+   if (!retro_resampler_realloc(&data, &resampler,
+         resampler_ident, quality, ratio))
+      return false;
+
+   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
+    * add 16 more samples in the formula below just as safeguard, because
+    * resampler->process sometimes reports more output samples than the
+    * formula below calculates. Ideally, audio resamplers should have a
+    * function to return the number of samples they will output given a
+    * count of input samples. */
+   *samples_out                       = (size_t)(samples_in * ratio);
+   *out                               = (float*)memalign_alloc(16,
+         (((*samples_out + 16) + 15) & ~15) * sizeof(float));
+
+   if (*out == NULL)
+      return false;
+
+   info.data_in                       = in;
+   info.data_out                      = *out;
+   info.input_frames                  = samples_in / 2;
+   info.output_frames                 = 0;
+   info.ratio                         = ratio;
+
+   resampler->process(data, &info);
+   resampler->free(data);
+   return true;
+}
+#endif
+
+void audio_mixer_init(unsigned rate)
+{
+   unsigned i;
+
+   s_rate = rate;
+
+   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)
+   {
+      audio_mixer_voice_t *voice = &s_voices[i];
+
+      voice->type = AUDIO_MIXER_TYPE_NONE;
+#ifdef HAVE_THREADS
+      if (!voice->lock)
+         voice->lock = slock_new();
+#endif
+   }
+}
+
+void audio_mixer_done(void)
+{
+   unsigned i;
+
+   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)
+   {
+      audio_mixer_voice_t *voice = &s_voices[i];
+
+      AUDIO_MIXER_LOCK(voice);
+      audio_mixer_release(voice);
+      AUDIO_MIXER_UNLOCK(voice);
+#ifdef HAVE_THREADS
+      slock_free(voice->lock);
+      voice->lock = NULL;
+#endif
+   }
+}
+
+audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,
+      const char *resampler_ident, enum resampler_quality quality)
+{
+#ifdef HAVE_RWAV
+   /* WAV data */
+   rwav_t wav;
+   /* WAV samples converted to float */
+   float* pcm                 = NULL;
+   size_t samples             = 0;
+   /* Result */
+   audio_mixer_sound_t* sound = NULL;
+
+   wav.bitspersample          = 0;
+   wav.numchannels            = 0;
+   wav.samplerate             = 0;
+   wav.numsamples             = 0;
+   wav.subchunk2size          = 0;
+   wav.samples                = NULL;
+
+   if ((rwav_load(&wav, buffer, size)) != RWAV_ITERATE_DONE)
+      return NULL;
+
+   samples       = wav.numsamples * 2;
+
+   if (!wav_to_float(&wav, &pcm, samples))
+      return NULL;
+
+   if (wav.samplerate != s_rate)
+   {
+      float* resampled           = NULL;
+
+      if (!one_shot_resample(pcm, samples, wav.samplerate,
+            resampler_ident, quality,
+            &resampled, &samples))
+         return NULL;
+
+      memalign_free((void*)pcm);
+      pcm = resampled;
+   }
+
+   sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));
+
+   if (!sound)
+   {
+      memalign_free((void*)pcm);
+      return NULL;
+   }
+
+   sound->type             = AUDIO_MIXER_TYPE_WAV;
+   sound->types.wav.frames = (unsigned)(samples / 2);
+   sound->types.wav.pcm    = pcm;
+
+   rwav_free(&wav);
+
+   return sound;
+#else
+   return NULL;
+#endif
+}
+
+audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size)
+{
+#ifdef HAVE_STB_VORBIS
+   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));
+
+   if (!sound)
+      return NULL;
+
+   sound->type           = AUDIO_MIXER_TYPE_OGG;
+   sound->types.ogg.size = size;
+   sound->types.ogg.data = buffer;
+
+   return sound;
+#else
+   return NULL;
+#endif
+}
+
+audio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size)
+{
+#ifdef HAVE_DR_FLAC
+   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));
+
+   if (!sound)
+      return NULL;
+
+   sound->type           = AUDIO_MIXER_TYPE_FLAC;
+   sound->types.flac.size = size;
+   sound->types.flac.data = buffer;
+
+   return sound;
+#else
+   return NULL;
+#endif
+}
+
+audio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size)
+{
+#ifdef HAVE_DR_MP3
+   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));
+
+   if (!sound)
+      return NULL;
+
+   sound->type           = AUDIO_MIXER_TYPE_MP3;
+   sound->types.mp3.size = size;
+   sound->types.mp3.data = buffer;
+
+   return sound;
+#else
+   return NULL;
+#endif
+}
+
+audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size)
+{
+#ifdef HAVE_IBXM
+   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));
+
+   if (!sound)
+      return NULL;
+
+   sound->type           = AUDIO_MIXER_TYPE_MOD;
+   sound->types.mod.size = size;
+   sound->types.mod.data = buffer;
+
+   return sound;
+#else
+   return NULL;
+#endif
+}
+
+void audio_mixer_destroy(audio_mixer_sound_t* sound)
+{
+   void *handle = NULL;
+   if (!sound)
+      return;
+
+   switch (sound->type)
+   {
+      case AUDIO_MIXER_TYPE_WAV:
+         handle = (void*)sound->types.wav.pcm;
+         if (handle)
+            memalign_free(handle);
+         break;
+      case AUDIO_MIXER_TYPE_OGG:
+#ifdef HAVE_STB_VORBIS
+         handle = (void*)sound->types.ogg.data;
+         if (handle)
+            free(handle);
+#endif
+         break;
+      case AUDIO_MIXER_TYPE_MOD:
+#ifdef HAVE_IBXM
+         handle = (void*)sound->types.mod.data;
+         if (handle)
+            free(handle);
+#endif
+         break;
+      case AUDIO_MIXER_TYPE_FLAC:
+#ifdef HAVE_DR_FLAC
+         handle = (void*)sound->types.flac.data;
+         if (handle)
+            free(handle);
+#endif
+         break;
+      case AUDIO_MIXER_TYPE_MP3:
+#ifdef HAVE_DR_MP3
+         handle = (void*)sound->types.mp3.data;
+         if (handle)
+            free(handle);
+#endif
+         break;
+      case AUDIO_MIXER_TYPE_NONE:
+         break;
+   }
+
+   free(sound);
+}
+
+static bool audio_mixer_play_wav(audio_mixer_sound_t* sound,
+      audio_mixer_voice_t* voice, bool repeat, float volume,
+      audio_mixer_stop_cb_t stop_cb)
+{
+   voice->types.wav.position = 0;
+   return true;
+}
+
+#ifdef HAVE_STB_VORBIS
+static bool audio_mixer_play_ogg(
+      audio_mixer_sound_t* sound,
+      audio_mixer_voice_t* voice,
+      bool repeat, float volume,
+      const char *resampler_ident,
+      enum resampler_quality quality,
+      audio_mixer_stop_cb_t stop_cb)
+{
+   stb_vorbis_info info;
+   int res                         = 0;
+   float ratio                     = 1.0f;
+   unsigned samples                = 0;
+   void *ogg_buffer                = NULL;
+   void *resampler_data            = NULL;
+   const retro_resampler_t* resamp = NULL;
+   stb_vorbis *stb_vorbis          = stb_vorbis_open_memory(
+         (const unsigned char*)sound->types.ogg.data,
+         sound->types.ogg.size, &res, NULL);
+
+   if (!stb_vorbis)
+      return false;
+
+   info                    = stb_vorbis_get_info(stb_vorbis);
+
+   if (info.sample_rate != s_rate)
+   {
+      ratio = (double)s_rate / (double)info.sample_rate;
+
+      if (!retro_resampler_realloc(&resampler_data,
+               &resamp, resampler_ident, quality,
+               ratio))
+         goto error;
+   }
+
+   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
+    * add 16 more samples in the formula below just as safeguard, because
+    * resampler->process sometimes reports more output samples than the
+    * formula below calculates. Ideally, audio resamplers should have a
+    * function to return the number of samples they will output given a
+    * count of input samples. */
+   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
+   ogg_buffer                      = (float*)memalign_alloc(16,
+         (((samples + 16) + 15) & ~15) * sizeof(float));
+
+   if (!ogg_buffer)
+   {
+      if (resamp && resampler_data)
+         resamp->free(resampler_data);
+      goto error;
+   }
+
+   voice->types.ogg.resampler      = resamp;
+   voice->types.ogg.resampler_data = resampler_data;
+   voice->types.ogg.buffer         = (float*)ogg_buffer;
+   voice->types.ogg.buf_samples    = samples;
+   voice->types.ogg.ratio          = ratio;
+   voice->types.ogg.stream         = stb_vorbis;
+   voice->types.ogg.position       = 0;
+   voice->types.ogg.samples        = 0;
+
+   return true;
+
+error:
+   stb_vorbis_close(stb_vorbis);
+   return false;
+}
+
+static void audio_mixer_release_ogg(audio_mixer_voice_t* voice)
+{
+   if (voice->types.ogg.stream)
+      stb_vorbis_close(voice->types.ogg.stream);
+   if (voice->types.ogg.resampler && voice->types.ogg.resampler_data)
+      voice->types.ogg.resampler->free(voice->types.ogg.resampler_data);
+   if (voice->types.ogg.buffer)
+      memalign_free(voice->types.ogg.buffer);
+}
+
+#endif
+
+#ifdef HAVE_IBXM
+static bool audio_mixer_play_mod(
+      audio_mixer_sound_t* sound,
+      audio_mixer_voice_t* voice,
+      bool repeat, float volume,
+      audio_mixer_stop_cb_t stop_cb)
+{
+   struct data data;
+   char message[64];
+   int buf_samples               = 0;
+   int samples                   = 0;
+   void *mod_buffer              = NULL;
+   struct module* module         = NULL;
+   struct replay* replay         = NULL;
+
+   data.buffer                   = (char*)sound->types.mod.data;
+   data.length                   = sound->types.mod.size;
+   module                        = module_load(&data, message);
+
+   if (!module)
+   {
+      printf("audio_mixer_play_mod module_load() failed with error: %s\n", message);
+      goto error;
+   }
+
+   if (voice->types.mod.module)
+      dispose_module(voice->types.mod.module);
+
+   voice->types.mod.module = module;
+
+   replay = new_replay(module, s_rate, 1);
+
+   if (!replay)
+   {
+      printf("audio_mixer_play_mod new_replay() failed\n");
+      goto error;
+   }
+
+   buf_samples = calculate_mix_buf_len(s_rate);
+   mod_buffer  = memalign_alloc(16, ((buf_samples + 15) & ~15) * sizeof(int));
+
+   if (!mod_buffer)
+   {
+      printf("audio_mixer_play_mod cannot allocate mod_buffer !\n");
+      goto error;
+   }
+
+   samples = replay_calculate_duration(replay);
+
+   if (!samples)
+   {
+      printf("audio_mixer_play_mod cannot retrieve duration !\n");
+      goto error;
+   }
+
+   voice->types.mod.buffer         = (int*)mod_buffer;
+   voice->types.mod.buf_samples    = buf_samples;
+   voice->types.mod.stream         = replay;
+   voice->types.mod.position       = 0;
+   voice->types.mod.samples        = 0; /* samples; */
+
+   return true;
+
+error:
+   if (mod_buffer)
+      memalign_free(mod_buffer);
+   if (module)
+      dispose_module(module);
+   return false;
+
+}
+
+static void audio_mixer_release_mod(audio_mixer_voice_t* voice)
+{
+   if (voice->types.mod.stream)
+      dispose_replay(voice->types.mod.stream);
+   if (voice->types.mod.buffer)
+      memalign_free(voice->types.mod.buffer);
+}
+#endif
+
+#ifdef HAVE_DR_FLAC
+static bool audio_mixer_play_flac(
+      audio_mixer_sound_t* sound,
+      audio_mixer_voice_t* voice,
+      bool repeat, float volume,
+      const char *resampler_ident,
+      enum resampler_quality quality,
+      audio_mixer_stop_cb_t stop_cb)
+{
+   float ratio                     = 1.0f;
+   unsigned samples                = 0;
+   void *flac_buffer                = NULL;
+   void *resampler_data            = NULL;
+   const retro_resampler_t* resamp = NULL;
+   drflac *dr_flac          = drflac_open_memory((const unsigned char*)sound->types.flac.data,sound->types.flac.size);
+
+   if (!dr_flac)
+      return false;
+   if (dr_flac->sampleRate != s_rate)
+   {
+      ratio = (double)s_rate / (double)(dr_flac->sampleRate);
+
+      if (!retro_resampler_realloc(&resampler_data,
+               &resamp, resampler_ident, quality,
+               ratio))
+         goto error;
+   }
+
+   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
+    * add 16 more samples in the formula below just as safeguard, because
+    * resampler->process sometimes reports more output samples than the
+    * formula below calculates. Ideally, audio resamplers should have a
+    * function to return the number of samples they will output given a
+    * count of input samples. */
+   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
+   flac_buffer                     = (float*)memalign_alloc(16,
+         (((samples + 16) + 15) & ~15) * sizeof(float));
+
+   if (!flac_buffer)
+   {
+      if (resamp && resamp->free)
+         resamp->free(resampler_data);
+      goto error;
+   }
+
+   voice->types.flac.resampler      = resamp;
+   voice->types.flac.resampler_data = resampler_data;
+   voice->types.flac.buffer         = (float*)flac_buffer;
+   voice->types.flac.buf_samples    = samples;
+   voice->types.flac.ratio          = ratio;
+   voice->types.flac.stream         = dr_flac;
+   voice->types.flac.position       = 0;
+   voice->types.flac.samples        = 0;
+
+   return true;
+
+error:
+   drflac_close(dr_flac);
+   return false;
+}
+
+static void audio_mixer_release_flac(audio_mixer_voice_t* voice)
+{
+   if (voice->types.flac.stream)
+      drflac_close(voice->types.flac.stream);
+   if (voice->types.flac.resampler && voice->types.flac.resampler_data)
+      voice->types.flac.resampler->free(voice->types.flac.resampler_data);
+   if (voice->types.flac.buffer)
+      memalign_free(voice->types.flac.buffer);
+}
+#endif
+
+#ifdef HAVE_DR_MP3
+static bool audio_mixer_play_mp3(
+      audio_mixer_sound_t* sound,
+      audio_mixer_voice_t* voice,
+      bool repeat, float volume,
+      const char *resampler_ident,
+      enum resampler_quality quality,
+      audio_mixer_stop_cb_t stop_cb)
+{
+   float ratio                     = 1.0f;
+   unsigned samples                = 0;
+   void *mp3_buffer                = NULL;
+   void *resampler_data            = NULL;
+   const retro_resampler_t* resamp = NULL;
+   bool res;
+
+   res = drmp3_init_memory(&voice->types.mp3.stream, (const unsigned char*)sound->types.mp3.data, sound->types.mp3.size, NULL);
+
+   if (!res)
+      return false;
+
+   if (voice->types.mp3.stream.sampleRate != s_rate)
+   {
+      ratio = (double)s_rate / (double)(voice->types.mp3.stream.sampleRate);
+
+      if (!retro_resampler_realloc(&resampler_data,
+               &resamp, resampler_ident, quality,
+               ratio))
+         goto error;
+   }
+
+   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We
+    * add 16 more samples in the formula below just as safeguard, because
+    * resampler->process sometimes reports more output samples than the
+    * formula below calculates. Ideally, audio resamplers should have a
+    * function to return the number of samples they will output given a
+    * count of input samples. */
+   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);
+   mp3_buffer                      = (float*)memalign_alloc(16,
+         (((samples + 16) + 15) & ~15) * sizeof(float));
+
+   if (!mp3_buffer)
+   {
+      if (resamp && resampler_data)
+         resamp->free(resampler_data);
+      goto error;
+   }
+
+   voice->types.mp3.resampler      = resamp;
+   voice->types.mp3.resampler_data = resampler_data;
+   voice->types.mp3.buffer         = (float*)mp3_buffer;
+   voice->types.mp3.buf_samples    = samples;
+   voice->types.mp3.ratio          = ratio;
+   voice->types.mp3.position       = 0;
+   voice->types.mp3.samples        = 0;
+
+   return true;
+
+error:
+   drmp3_uninit(&voice->types.mp3.stream);
+   return false;
+}
+
+static void audio_mixer_release_mp3(audio_mixer_voice_t* voice)
+{
+   if (voice->types.mp3.resampler && voice->types.mp3.resampler_data)
+      voice->types.mp3.resampler->free(voice->types.mp3.resampler_data);
+   if (voice->types.mp3.buffer)
+      memalign_free(voice->types.mp3.buffer);
+   if (voice->types.mp3.stream.pData)
+      drmp3_uninit(&voice->types.mp3.stream);
+}
+
+#endif
+
+audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
+      bool repeat, float volume,
+      const char *resampler_ident,
+      enum resampler_quality quality,
+      audio_mixer_stop_cb_t stop_cb)
+{
+   unsigned i;
+   bool res                   = false;
+   audio_mixer_voice_t* voice = s_voices;
+
+   if (!sound)
+      return NULL;
+
+   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
+   {
+      if (voice->type != AUDIO_MIXER_TYPE_NONE)
+         continue;
+
+      AUDIO_MIXER_LOCK(voice);
+
+      if (voice->type != AUDIO_MIXER_TYPE_NONE)
+      {
+         AUDIO_MIXER_UNLOCK(voice);
+         continue;
+      }
+
+      /* claim the voice, also helps with cleanup on error */
+      voice->type = sound->type;
+
+      switch (sound->type)
+      {
+         case AUDIO_MIXER_TYPE_WAV:
+            res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb);
+            break;
+         case AUDIO_MIXER_TYPE_OGG:
+#ifdef HAVE_STB_VORBIS
+            res = audio_mixer_play_ogg(sound, voice, repeat, volume,
+                  resampler_ident, quality, stop_cb);
+#endif
+            break;
+         case AUDIO_MIXER_TYPE_MOD:
+#ifdef HAVE_IBXM
+            res = audio_mixer_play_mod(sound, voice, repeat, volume, stop_cb);
+#endif
+            break;
+         case AUDIO_MIXER_TYPE_FLAC:
+#ifdef HAVE_DR_FLAC
+            res = audio_mixer_play_flac(sound, voice, repeat, volume,
+                  resampler_ident, quality, stop_cb);
+#endif
+            break;
+         case AUDIO_MIXER_TYPE_MP3:
+#ifdef HAVE_DR_MP3
+            res = audio_mixer_play_mp3(sound, voice, repeat, volume,
+                  resampler_ident, quality, stop_cb);
+#endif
+            break;
+         case AUDIO_MIXER_TYPE_NONE:
+            break;
+      }
+
+      break;
+   }
+
+   if (res)
+   {
+      voice->repeat   = repeat;
+      voice->volume   = volume;
+      voice->sound    = sound;
+      voice->stop_cb  = stop_cb;
+      AUDIO_MIXER_UNLOCK(voice);
+   }
+   else
+   {
+      if (i < AUDIO_MIXER_MAX_VOICES)
+      {
+         audio_mixer_release(voice);
+         AUDIO_MIXER_UNLOCK(voice);
+      }
+      voice = NULL;
+   }
+
+   return voice;
+}
+
+/* Need to hold lock for voice.  */
+static void audio_mixer_release(audio_mixer_voice_t* voice)
+{
+   if (!voice)
+      return;
+
+   switch (voice->type)
+   {
+#ifdef HAVE_STB_VORBIS
+      case AUDIO_MIXER_TYPE_OGG:
+         audio_mixer_release_ogg(voice);
+         break;
+#endif
+#ifdef HAVE_IBXM
+      case AUDIO_MIXER_TYPE_MOD:
+         audio_mixer_release_mod(voice);
+         break;
+#endif
+#ifdef HAVE_DR_FLAC
+      case AUDIO_MIXER_TYPE_FLAC:
+         audio_mixer_release_flac(voice);
+         break;
+#endif
+#ifdef HAVE_DR_MP3
+      case AUDIO_MIXER_TYPE_MP3:
+         audio_mixer_release_mp3(voice);
+         break;
+#endif
+      default:
+         break;
+   }
+
+   memset(&voice->types, 0, sizeof(voice->types));
+   voice->type = AUDIO_MIXER_TYPE_NONE;
+}
+
+void audio_mixer_stop(audio_mixer_voice_t* voice)
+{
+   audio_mixer_stop_cb_t stop_cb = NULL;
+   audio_mixer_sound_t* sound    = NULL;
+
+   if (voice)
+   {
+      AUDIO_MIXER_LOCK(voice);
+      stop_cb     = voice->stop_cb;
+      sound       = voice->sound;
+
+      audio_mixer_release(voice);
+
+      AUDIO_MIXER_UNLOCK(voice);
+
+      if (stop_cb)
+         stop_cb(sound, AUDIO_MIXER_SOUND_STOPPED);
+   }
+}
+
+static void audio_mixer_mix_wav(float* buffer, size_t num_frames,
+      audio_mixer_voice_t* voice,
+      float volume)
+{
+   int i;
+   unsigned buf_free                = (unsigned)(num_frames * 2);
+   const audio_mixer_sound_t* sound = voice->sound;
+   unsigned pcm_available           = sound->types.wav.frames
+      * 2 - voice->types.wav.position;
+   const float* pcm                 = sound->types.wav.pcm +
+      voice->types.wav.position;
+
+again:
+   if (pcm_available < buf_free)
+   {
+      for (i = pcm_available; i != 0; i--)
+         *buffer++ += *pcm++ * volume;
+
+      if (voice->repeat)
+      {
+         if (voice->stop_cb)
+            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);
+
+         buf_free                  -= pcm_available;
+         pcm_available              = sound->types.wav.frames * 2;
+         pcm                        = sound->types.wav.pcm;
+         voice->types.wav.position  = 0;
+         goto again;
+      }
+
+      if (voice->stop_cb)
+         voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
+
+      audio_mixer_release(voice);
+   }
+   else
+   {
+      for (i = buf_free; i != 0; i--)
+         *buffer++ += *pcm++ * volume;
+
+      voice->types.wav.position += buf_free;
+   }
+}
+
+#ifdef HAVE_STB_VORBIS
+static void audio_mixer_mix_ogg(float* buffer, size_t num_frames,
+      audio_mixer_voice_t* voice,
+      float volume)
+{
+   int i;
+   float* temp_buffer = NULL;
+   unsigned buf_free                = (unsigned)(num_frames * 2);
+   unsigned temp_samples            = 0;
+   float* pcm                       = NULL;
+
+   if (!voice->types.ogg.stream)
+      return;
+
+   if (voice->types.ogg.position == voice->types.ogg.samples)
+   {
+again:
+      if (temp_buffer == NULL)
+         temp_buffer = (float*)malloc(AUDIO_MIXER_TEMP_BUFFER * sizeof(float));
+
+      temp_samples = stb_vorbis_get_samples_float_interleaved(
+            voice->types.ogg.stream, 2, temp_buffer,
+            AUDIO_MIXER_TEMP_BUFFER) * 2;
+
+      if (temp_samples == 0)
+      {
+         if (voice->repeat)
+         {
+            if (voice->stop_cb)
+               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);
+
+            stb_vorbis_seek_start(voice->types.ogg.stream);
+            goto again;
+         }
+
+         if (voice->stop_cb)
+            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
+
+         audio_mixer_release(voice);
+         goto cleanup;
+      }
+
+      if (voice->types.ogg.resampler)
+      {
+         struct resampler_data info;
+         info.data_in = temp_buffer;
+         info.data_out = voice->types.ogg.buffer;
+         info.input_frames = temp_samples / 2;
+         info.output_frames = 0;
+         info.ratio = voice->types.ogg.ratio;
+
+         voice->types.ogg.resampler->process(
+               voice->types.ogg.resampler_data, &info);
+      }
+      else
+         memcpy(voice->types.ogg.buffer, temp_buffer,
+               temp_samples * sizeof(float));
+
+      voice->types.ogg.position = 0;
+      voice->types.ogg.samples  = voice->types.ogg.buf_samples;
+   }
+
+   pcm = voice->types.ogg.buffer + voice->types.ogg.position;
+
+   if (voice->types.ogg.samples < buf_free)
+   {
+      for (i = voice->types.ogg.samples; i != 0; i--)
+         *buffer++ += *pcm++ * volume;
+
+      buf_free -= voice->types.ogg.samples;
+      goto again;
+   }
+
+   for (i = buf_free; i != 0; --i )
+      *buffer++ += *pcm++ * volume;
+
+   voice->types.ogg.position += buf_free;
+   voice->types.ogg.samples  -= buf_free;
+
+cleanup:
+   if (temp_buffer != NULL)
+      free(temp_buffer);
+}
+#endif
+
+#ifdef HAVE_IBXM
+static void audio_mixer_mix_mod(float* buffer, size_t num_frames,
+      audio_mixer_voice_t* voice,
+      float volume)
+{
+   int i;
+   float samplef                    = 0.0f;
+   unsigned temp_samples            = 0;
+   unsigned buf_free                = (unsigned)(num_frames * 2);
+   int* pcm                         = NULL;
+
+   if (voice->types.mod.samples == 0)
+   {
+again:
+      temp_samples = replay_get_audio(
+            voice->types.mod.stream, voice->types.mod.buffer, 0 ) * 2;
+
+      if (temp_samples == 0)
+      {
+         if (voice->repeat)
+         {
+            if (voice->stop_cb)
+               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);
+
+            replay_seek( voice->types.mod.stream, 0);
+            goto again;
+         }
+
+         if (voice->stop_cb)
+            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
+
+         audio_mixer_release(voice);
+         return;
+      }
+
+      voice->types.mod.position = 0;
+      voice->types.mod.samples  = temp_samples;
+   }
+   pcm = voice->types.mod.buffer + voice->types.mod.position;
+
+   if (voice->types.mod.samples < buf_free)
+   {
+      for (i = voice->types.mod.samples; i != 0; i--)
+      {
+         samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;
+         samplef     = samplef * 2.0f - 1.0f;
+         *buffer++  += samplef * volume;
+      }
+
+      buf_free -= voice->types.mod.samples;
+      goto again;
+   }
+
+   for (i = buf_free; i != 0; --i )
+   {
+      samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;
+      samplef     = samplef * 2.0f - 1.0f;
+      *buffer++  += samplef * volume;
+   }
+
+   voice->types.mod.position += buf_free;
+   voice->types.mod.samples  -= buf_free;
+}
+#endif
+
+#ifdef HAVE_DR_FLAC
+static void audio_mixer_mix_flac(float* buffer, size_t num_frames,
+      audio_mixer_voice_t* voice,
+      float volume)
+{
+   int i;
+   struct resampler_data info;
+   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
+   unsigned buf_free                = (unsigned)(num_frames * 2);
+   unsigned temp_samples            = 0;
+   float *pcm                       = NULL;
+
+   if (voice->types.flac.position == voice->types.flac.samples)
+   {
+again:
+      temp_samples = (unsigned)drflac_read_f32( voice->types.flac.stream, AUDIO_MIXER_TEMP_BUFFER, temp_buffer);
+      if (temp_samples == 0)
+      {
+         if (voice->repeat)
+         {
+            if (voice->stop_cb)
+               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);
+
+            drflac_seek_to_sample(voice->types.flac.stream,0);
+            goto again;
+         }
+
+         if (voice->stop_cb)
+            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
+
+         audio_mixer_release(voice);
+         return;
+      }
+
+      info.data_in              = temp_buffer;
+      info.data_out             = voice->types.flac.buffer;
+      info.input_frames         = temp_samples / 2;
+      info.output_frames        = 0;
+      info.ratio                = voice->types.flac.ratio;
+
+      if (voice->types.flac.resampler)
+         voice->types.flac.resampler->process(
+               voice->types.flac.resampler_data, &info);
+      else
+         memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float));
+      voice->types.flac.position = 0;
+      voice->types.flac.samples  = voice->types.flac.buf_samples;
+   }
+
+   pcm = voice->types.flac.buffer + voice->types.flac.position;
+
+   if (voice->types.flac.samples < buf_free)
+   {
+      for (i = voice->types.flac.samples; i != 0; i--)
+         *buffer++ += *pcm++ * volume;
+
+      buf_free -= voice->types.flac.samples;
+      goto again;
+   }
+
+   for (i = buf_free; i != 0; --i )
+      *buffer++ += *pcm++ * volume;
+
+   voice->types.flac.position += buf_free;
+   voice->types.flac.samples  -= buf_free;
+}
+#endif
+
+#ifdef HAVE_DR_MP3
+static void audio_mixer_mix_mp3(float* buffer, size_t num_frames,
+      audio_mixer_voice_t* voice,
+      float volume)
+{
+   int i;
+   struct resampler_data info;
+   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
+   unsigned buf_free                = (unsigned)(num_frames * 2);
+   unsigned temp_samples            = 0;
+   float* pcm                       = NULL;
+
+   if (voice->types.mp3.position == voice->types.mp3.samples)
+   {
+again:
+      temp_samples = (unsigned)drmp3_read_f32(
+            &voice->types.mp3.stream,
+            AUDIO_MIXER_TEMP_BUFFER / 2, temp_buffer) * 2;
+
+      if (temp_samples == 0)
+      {
+         if (voice->repeat)
+         {
+            if (voice->stop_cb)
+               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);
+
+            drmp3_seek_to_frame(&voice->types.mp3.stream,0);
+            goto again;
+         }
+
+         if (voice->stop_cb)
+            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
+
+         audio_mixer_release(voice);
+         return;
+      }
+
+      info.data_in              = temp_buffer;
+      info.data_out             = voice->types.mp3.buffer;
+      info.input_frames         = temp_samples / 2;
+      info.output_frames        = 0;
+      info.ratio                = voice->types.mp3.ratio;
+
+      if (voice->types.mp3.resampler)
+         voice->types.mp3.resampler->process(
+               voice->types.mp3.resampler_data, &info);
+      else
+         memcpy(voice->types.mp3.buffer, temp_buffer,
+               temp_samples * sizeof(float));
+      voice->types.mp3.position = 0;
+      voice->types.mp3.samples  = voice->types.mp3.buf_samples;
+   }
+
+   pcm = voice->types.mp3.buffer + voice->types.mp3.position;
+
+   if (voice->types.mp3.samples < buf_free)
+   {
+      for (i = voice->types.mp3.samples; i != 0; i--)
+         *buffer++ += *pcm++ * volume;
+
+      buf_free -= voice->types.mp3.samples;
+      goto again;
+   }
+
+   for (i = buf_free; i != 0; --i )
+      *buffer++ += *pcm++ * volume;
+
+   voice->types.mp3.position += buf_free;
+   voice->types.mp3.samples  -= buf_free;
+}
+#endif
+
+void audio_mixer_mix(float* buffer, size_t num_frames,
+      float volume_override, bool override)
+{
+   unsigned i;
+   size_t j                   = 0;
+   float* sample              = NULL;
+   audio_mixer_voice_t* voice = s_voices;
+
+   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)
+   {
+      float volume;
+
+      AUDIO_MIXER_LOCK(voice);
+
+      volume = (override) ? volume_override : voice->volume;
+
+      switch (voice->type)
+      {
+         case AUDIO_MIXER_TYPE_WAV:
+            audio_mixer_mix_wav(buffer, num_frames, voice, volume);
+            break;
+         case AUDIO_MIXER_TYPE_OGG:
+#ifdef HAVE_STB_VORBIS
+            audio_mixer_mix_ogg(buffer, num_frames, voice, volume);
+#endif
+            break;
+         case AUDIO_MIXER_TYPE_MOD:
+#ifdef HAVE_IBXM
+            audio_mixer_mix_mod(buffer, num_frames, voice, volume);
+#endif
+            break;
+         case AUDIO_MIXER_TYPE_FLAC:
+#ifdef HAVE_DR_FLAC
+            audio_mixer_mix_flac(buffer, num_frames, voice, volume);
+#endif
+            break;
+            case AUDIO_MIXER_TYPE_MP3:
+#ifdef HAVE_DR_MP3
+            audio_mixer_mix_mp3(buffer, num_frames, voice, volume);
+#endif
+            break;
+         case AUDIO_MIXER_TYPE_NONE:
+            break;
+      }
+
+      AUDIO_MIXER_UNLOCK(voice);
+   }
+
+   for (j = 0, sample = buffer; j < num_frames * 2; j++, sample++)
+   {
+      if (*sample < -1.0f)
+         *sample = -1.0f;
+      else if (*sample > 1.0f)
+         *sample = 1.0f;
+   }
+}
+
+float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice)
+{
+   if (!voice)
+      return 0.0f;
+
+   return voice->volume;
+}
+
+void audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val)
+{
+   if (!voice)
+      return;
+
+   AUDIO_MIXER_LOCK(voice);
+   voice->volume = val;
+   AUDIO_MIXER_UNLOCK(voice);
+}
diff --git a/deps/libretro-common/audio/conversion/float_to_s16.c b/deps/libretro-common/audio/conversion/float_to_s16.c
new file mode 100644 (file)
index 0000000..6f65fe1
--- /dev/null
@@ -0,0 +1,183 @@
+/* Copyright  (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (float_to_s16.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#if defined(__SSE2__)
+#include <emmintrin.h>
+#elif defined(__ALTIVEC__)
+#include <altivec.h>
+#endif
+
+#include <features/features_cpu.h>
+#include <audio/conversion/float_to_s16.h>
+
+#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
+static bool float_to_s16_neon_enabled = false;
+#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
+void convert_float_s16_asm(int16_t *out,
+      const float *in, size_t samples);
+#else
+#include <arm_neon.h>
+#endif
+
+void convert_float_to_s16(int16_t *out,
+      const float *in, size_t samples)
+{
+   size_t i           = 0;
+   if (float_to_s16_neon_enabled)
+   {
+      float        gf = (1<<15);
+      float32x4_t vgf = {gf, gf, gf, gf};
+      while (samples >= 8)
+      {
+#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
+         size_t aligned_samples = samples & ~7;
+         if (aligned_samples)
+            convert_float_s16_asm(out, in, aligned_samples);
+
+         out                += aligned_samples;
+         in                 += aligned_samples;
+         samples            -= aligned_samples;
+         i                   = 0;
+#else
+         int16x4x2_t oreg;
+         int32x4x2_t creg;
+         float32x4x2_t inreg = vld2q_f32(in);
+         creg.val[0]         = vcvtq_s32_f32(vmulq_f32(inreg.val[0], vgf));
+         creg.val[1]         = vcvtq_s32_f32(vmulq_f32(inreg.val[1], vgf));
+         oreg.val[0]         = vqmovn_s32(creg.val[0]);
+         oreg.val[1]         = vqmovn_s32(creg.val[1]);
+         vst2_s16(out, oreg);
+         in                 += 8;
+         out                += 8;
+         samples            -= 8;
+#endif
+      }
+   }
+
+   for (; i < samples; i++)
+   {
+      int32_t val = (int32_t)(in[i] * 0x8000);
+      out[i]      = (val > 0x7FFF) ? 0x7FFF :
+         (val < -0x8000 ? -0x8000 : (int16_t)val);
+   }
+}
+
+void convert_float_to_s16_init_simd(void)
+{
+   uint64_t cpu = cpu_features_get();
+
+   if (cpu & RETRO_SIMD_NEON)
+      float_to_s16_neon_enabled = true;
+}
+#else
+void convert_float_to_s16(int16_t *out,
+      const float *in, size_t samples)
+{
+   size_t i          = 0;
+#if defined(__SSE2__)
+   __m128 factor     = _mm_set1_ps((float)0x8000);
+   /* Initialize a 4D vector with 32768.0 for its elements */
+
+   for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
+   { /* Skip forward 8 samples at a time... */
+      __m128 input_a = _mm_loadu_ps(in + 0); /* Create a 4-float vector from the next four samples... */
+      __m128 input_b = _mm_loadu_ps(in + 4); /* ...and another from the *next* next four. */
+      __m128 res_a   = _mm_mul_ps(input_a, factor);
+      __m128 res_b   = _mm_mul_ps(input_b, factor); /* Multiply these samples by 32768 */
+      __m128i ints_a = _mm_cvtps_epi32(res_a);
+      __m128i ints_b = _mm_cvtps_epi32(res_b); /* Convert the samples to 32-bit integers */
+      __m128i packed = _mm_packs_epi32(ints_a, ints_b); /* Then convert them to 16-bit ints, clamping to [-32768, 32767] */
+
+      _mm_storeu_si128((__m128i *)out, packed); /* Then put the result in the output array */
+   }
+
+   samples           = samples - i;
+   i                 = 0;
+   /* If there are any stray samples at the end, we need to convert them
+    * (maybe the original array didn't contain a multiple of 8 samples) */
+#elif defined(__ALTIVEC__)
+   int samples_in    = samples;
+
+   /* Unaligned loads/store is a bit expensive,
+    * so we optimize for the good path (very likely). */
+   if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
+   {
+      size_t i;
+      for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
+      {
+         vector float       input0 = vec_ld( 0, in);
+         vector float       input1 = vec_ld(16, in);
+         vector signed int result0 = vec_cts(input0, 15);
+         vector signed int result1 = vec_cts(input1, 15);
+         vec_st(vec_packs(result0, result1), 0, out);
+      }
+
+      samples_in    -= i;
+   }
+
+   samples           = samples_in;
+   i                 = 0;
+#elif defined(_MIPS_ARCH_ALLEGREX)
+#ifdef DEBUG
+   /* Make sure the buffers are 16 byte aligned, this should be
+    * the default behaviour of malloc in the PSPSDK.
+    * Assume alignment. */
+   retro_assert(((uintptr_t)in  & 0xf) == 0);
+   retro_assert(((uintptr_t)out & 0xf) == 0);
+#endif
+
+   for (i = 0; i + 8 <= samples; i += 8)
+   {
+      __asm__ (
+            ".set    push                 \n"
+            ".set    noreorder            \n"
+
+            "lv.q    c100,  0(%0)         \n"
+            "lv.q    c110,  16(%0)        \n"
+
+            "vf2in.q c100, c100, 31       \n"
+            "vf2in.q c110, c110, 31       \n"
+            "vi2s.q  c100, c100           \n"
+            "vi2s.q  c102, c110           \n"
+
+            "sv.q    c100,  0(%1)         \n"
+
+            ".set    pop                  \n"
+            :: "r"(in + i), "r"(out + i));
+   }
+#endif
+
+   /* This loop converts stray samples to the right format,
+    * but it's also a fallback in case no SIMD instructions are available. */
+   for (; i < samples; i++)
+   {
+      int32_t val    = (int32_t)(in[i] * 0x8000);
+      out[i]         = (val > 0x7FFF) 
+         ? 0x7FFF 
+         : (val < -0x8000 ? -0x8000 : (int16_t)val);
+   }
+}
+
+void convert_float_to_s16_init_simd(void) { }
+#endif
diff --git a/deps/libretro-common/audio/conversion/float_to_s16_neon.S b/deps/libretro-common/audio/conversion/float_to_s16_neon.S
new file mode 100644 (file)
index 0000000..951084f
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (float_to_s16_neon.S).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)
+
+#ifndef __MACH__
+.arm
+#endif
+
+.align 4
+.globl convert_float_s16_asm
+#ifndef __MACH__
+.type convert_float_s16_asm, %function
+#endif
+.globl _convert_float_s16_asm
+#ifndef __MACH__
+.type _convert_float_s16_asm, %function
+#endif
+# convert_float_s16_asm(int16_t *out, const float *in, size_t samples)
+convert_float_s16_asm:
+_convert_float_s16_asm:
+   # Hacky way to get a constant of 2^15.
+   # ((2^4)^2)^2 * 0.5 = 2^15
+   vmov.f32 q8, #16.0
+   vmov.f32 q9, #0.5
+   vmul.f32 q8, q8, q8
+   vmul.f32 q8, q8, q8
+   vmul.f32 q8, q8, q9
+
+1:
+   # Preload here?
+   vld1.f32 {q0-q1}, [r1]!
+
+   vmul.f32 q0, q0, q8
+   vmul.f32 q1, q1, q8
+
+   vcvt.s32.f32 q0, q0
+   vcvt.s32.f32 q1, q1
+
+   vqmovn.s32 d4, q0
+   vqmovn.s32 d5, q1
+
+   vst1.f32 {d4-d5}, [r0]!
+
+   # Guaranteed to get samples in multiples of 8.
+   subs r2, r2, #8
+   bne 1b
+
+   bx lr
+
+#endif
diff --git a/deps/libretro-common/audio/conversion/float_to_s16_neon.c b/deps/libretro-common/audio/conversion/float_to_s16_neon.c
new file mode 100644 (file)
index 0000000..85f4a96
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (float_to_s16_neon.S).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)
+
+#if defined(__thumb__)
+#define DECL_ARMMODE(x) "  .align 2\n" "  .global " x "\n" "  .thumb\n" "  .thumb_func\n" "  .type " x ", %function\n" x ":\n"
+#else
+#define DECL_ARMMODE(x) "  .align 4\n" "  .global " x "\n" "  .arm\n" x ":\n"
+#endif
+
+asm(
+    DECL_ARMMODE("convert_float_s16_asm")
+    DECL_ARMMODE("_convert_float_s16_asm")
+    "# convert_float_s16_asm(int16_t *out, const float *in, size_t samples)\n"
+    "   # Hacky way to get a constant of 2^15.\n"
+    "   # ((2^4)^2)^2 * 0.5 = 2^15\n"
+    "   vmov.f32 q8, #16.0\n"
+    "   vmov.f32 q9, #0.5\n"
+    "   vmul.f32 q8, q8, q8\n"
+    "   vmul.f32 q8, q8, q8\n"
+    "   vmul.f32 q8, q8, q9\n"
+    "\n"
+    "1:\n"
+    "   # Preload here?\n"
+    "   vld1.f32 {q0-q1}, [r1]!\n"
+    "\n"
+    "   vmul.f32 q0, q0, q8\n"
+    "   vmul.f32 q1, q1, q8\n"
+    "\n"
+    "   vcvt.s32.f32 q0, q0\n"
+    "   vcvt.s32.f32 q1, q1\n"
+    "\n"
+    "   vqmovn.s32 d4, q0\n"
+    "   vqmovn.s32 d5, q1\n"
+    "\n"
+    "   vst1.f32 {d4-d5}, [r0]!\n"
+    "\n"
+    "   # Guaranteed to get samples in multiples of 8.\n"
+    "   subs r2, r2, #8\n"
+    "   bne 1b\n"
+    "\n"
+    "   bx lr\n"
+    "\n"
+    );
+#endif
diff --git a/deps/libretro-common/audio/conversion/mono_to_stereo_float.c b/deps/libretro-common/audio/conversion/mono_to_stereo_float.c
new file mode 100644 (file)
index 0000000..838d8c2
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright  (C) 2010-2023 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (mono_to_stereo.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#include <audio/conversion/dual_mono.h>
+
+/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */
+void convert_to_dual_mono_float(float *out, const float *in, size_t frames)
+{
+   unsigned i = 0;
+
+   if (!out || !in || !frames)
+      return;
+
+   for (; i < frames; i++)
+   {
+      out[i * 2] = in[i];
+      out[i * 2 + 1] = in[i];
+   }
+}
+
+/* Why is there no equivalent for int16_t samples?
+ * No inherent reason, I just didn't need one.
+ * If you do, open a pull request. */
\ No newline at end of file
diff --git a/deps/libretro-common/audio/conversion/s16_to_float.c b/deps/libretro-common/audio/conversion/s16_to_float.c
new file mode 100644 (file)
index 0000000..03a836d
--- /dev/null
@@ -0,0 +1,205 @@
+/* Copyright  (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (s16_to_float.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+#if defined(__SSE2__)
+#include <emmintrin.h>
+#elif defined(__ALTIVEC__)
+#include <altivec.h>
+#endif
+
+#include <boolean.h>
+#include <features/features_cpu.h>
+#include <audio/conversion/s16_to_float.h>
+
+#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
+static bool s16_to_float_neon_enabled = false;
+
+#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
+/* Avoid potential hard-float/soft-float ABI issues. */
+void convert_s16_float_asm(float *out, const int16_t *in,
+      size_t samples, const float *gain);
+#else
+#include <arm_neon.h>
+#endif
+
+void convert_s16_to_float(float *out,
+      const int16_t *in, size_t samples, float gain)
+{
+   unsigned i      = 0;
+
+   if (s16_to_float_neon_enabled)
+   {
+#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
+      size_t aligned_samples = samples & ~7;
+      if (aligned_samples)
+         convert_s16_float_asm(out, in, aligned_samples, &gain);
+
+      /* Could do all conversion in ASM, but keep it simple for now. */
+      out                   += aligned_samples;
+      in                    += aligned_samples;
+      samples               -= aligned_samples;
+      i                      = 0;
+#else
+      float        gf        = gain / (1 << 15);
+      float32x4_t vgf        = {gf, gf, gf, gf};
+      while (samples >= 8)
+      {
+         float32x4x2_t oreg;
+         int16x4x2_t inreg   = vld2_s16(in);
+         int32x4_t      p1   = vmovl_s16(inreg.val[0]);
+         int32x4_t      p2   = vmovl_s16(inreg.val[1]);
+         oreg.val[0]         = vmulq_f32(vcvtq_f32_s32(p1), vgf);
+         oreg.val[1]         = vmulq_f32(vcvtq_f32_s32(p2), vgf);
+         vst2q_f32(out, oreg);
+         in                 += 8;
+         out                += 8;
+         samples            -= 8;
+      }
+#endif
+   }
+
+   gain /= 0x8000;
+
+   for (; i < samples; i++)
+      out[i] = (float)in[i] * gain;
+}
+
+void convert_s16_to_float_init_simd(void)
+{
+   uint64_t cpu = cpu_features_get();
+
+   if (cpu & RETRO_SIMD_NEON)
+      s16_to_float_neon_enabled = true;
+}
+#else
+void convert_s16_to_float(float *out,
+      const int16_t *in, size_t samples, float gain)
+{
+   unsigned i      = 0;
+
+#if defined(__SSE2__)
+   float fgain   = gain / UINT32_C(0x80000000);
+   __m128 factor = _mm_set1_ps(fgain);
+
+   for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
+   {
+      __m128i input    = _mm_loadu_si128((const __m128i *)in);
+      __m128i regs_l   = _mm_unpacklo_epi16(_mm_setzero_si128(), input);
+      __m128i regs_r   = _mm_unpackhi_epi16(_mm_setzero_si128(), input);
+      __m128 output_l  = _mm_mul_ps(_mm_cvtepi32_ps(regs_l), factor);
+      __m128 output_r  = _mm_mul_ps(_mm_cvtepi32_ps(regs_r), factor);
+
+      _mm_storeu_ps(out + 0, output_l);
+      _mm_storeu_ps(out + 4, output_r);
+   }
+
+   samples = samples - i;
+   i       = 0;
+#elif defined(__ALTIVEC__)
+   size_t samples_in = samples;
+
+   /* Unaligned loads/store is a bit expensive, so we
+    * optimize for the good path (very likely). */
+   if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
+   {
+      const vector float gain_vec = { gain, gain , gain, gain };
+      const vector float zero_vec = { 0.0f, 0.0f, 0.0f, 0.0f};
+
+      for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
+      {
+         vector signed short input = vec_ld(0, in);
+         vector signed int hi      = vec_unpackh(input);
+         vector signed int lo      = vec_unpackl(input);
+         vector float out_hi       = vec_madd(vec_ctf(hi, 15), gain_vec, zero_vec);
+         vector float out_lo       = vec_madd(vec_ctf(lo, 15), gain_vec, zero_vec);
+
+         vec_st(out_hi,  0, out);
+         vec_st(out_lo, 16, out);
+      }
+
+      samples_in -= i;
+   }
+
+   samples = samples_in;
+   i       = 0;
+#endif
+
+   gain   /= 0x8000;
+
+#if defined(_MIPS_ARCH_ALLEGREX)
+#ifdef DEBUG
+   /* Make sure the buffer is 16 byte aligned, this should be the
+    * default behaviour of malloc in the PSPSDK.
+    * Only the output buffer can be assumed to be 16-byte aligned. */
+   retro_assert(((uintptr_t)out & 0xf) == 0);
+#endif
+
+   __asm__ (
+         ".set    push                    \n"
+         ".set    noreorder               \n"
+         "mtv     %0, s200                \n"
+         ".set    pop                     \n"
+         ::"r"(gain));
+
+   for (i = 0; i + 16 <= samples; i += 16)
+   {
+      __asm__ (
+            ".set    push                 \n"
+            ".set    noreorder            \n"
+
+            "lv.s    s100,  0(%0)         \n"
+            "lv.s    s101,  4(%0)         \n"
+            "lv.s    s110,  8(%0)         \n"
+            "lv.s    s111, 12(%0)         \n"
+            "lv.s    s120, 16(%0)         \n"
+            "lv.s    s121, 20(%0)         \n"
+            "lv.s    s130, 24(%0)         \n"
+            "lv.s    s131, 28(%0)         \n"
+
+            "vs2i.p  c100, c100           \n"
+            "vs2i.p  c110, c110           \n"
+            "vs2i.p  c120, c120           \n"
+            "vs2i.p  c130, c130           \n"
+
+            "vi2f.q  c100, c100, 16       \n"
+            "vi2f.q  c110, c110, 16       \n"
+            "vi2f.q  c120, c120, 16       \n"
+            "vi2f.q  c130, c130, 16       \n"
+
+            "vmscl.q e100, e100, s200     \n"
+
+            "sv.q    c100,  0(%1)         \n"
+            "sv.q    c110, 16(%1)         \n"
+            "sv.q    c120, 32(%1)         \n"
+            "sv.q    c130, 48(%1)         \n"
+
+            ".set    pop                  \n"
+            :: "r"(in + i), "r"(out + i));
+   }
+#endif
+
+   for (; i < samples; i++)
+      out[i] = (float)in[i] * gain;
+}
+
+void convert_s16_to_float_init_simd(void) { }
+#endif
+
diff --git a/deps/libretro-common/audio/conversion/s16_to_float_neon.S b/deps/libretro-common/audio/conversion/s16_to_float_neon.S
new file mode 100644 (file)
index 0000000..6060214
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (s16_to_float_neon.S).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)
+
+#ifndef __MACH__
+.arm
+#endif
+
+.align 4
+.globl convert_s16_float_asm
+#ifndef __MACH__
+.type convert_s16_float_asm, %function
+#endif
+.globl _convert_s16_float_asm
+#ifndef __MACH__
+.type _convert_s16_float_asm, %function
+#endif
+# convert_s16_float_asm(float *out, const int16_t *in, size_t samples, const float *gain)
+convert_s16_float_asm:
+_convert_s16_float_asm:
+   # Hacky way to get a constant of 2^-15.
+   # Might be faster to just load a constant from memory.
+   # It's just done once however ...
+   vmov.f32 q8, #0.25
+   vmul.f32 q8, q8, q8
+   vmul.f32 q8, q8, q8
+   vmul.f32 q8, q8, q8
+   vadd.f32 q8, q8, q8
+
+   # Apply gain
+   vld1.f32 {d6[0]}, [r3]
+   vmul.f32 q8, q8, d6[0]
+
+1:
+   # Preload here?
+   vld1.s16 {q0}, [r1]!
+
+   # Widen to 32-bit
+   vmovl.s16 q1, d0
+   vmovl.s16 q2, d1
+
+   # Convert to float
+   vcvt.f32.s32 q1, q1
+   vcvt.f32.s32 q2, q2
+
+   vmul.f32 q1, q1, q8
+   vmul.f32 q2, q2, q8
+
+   vst1.f32 {q1-q2}, [r0]!
+
+   # Guaranteed to get samples in multiples of 8.
+   subs r2, r2, #8
+   bne 1b
+
+   bx lr
+
+#endif
diff --git a/deps/libretro-common/audio/conversion/s16_to_float_neon.c b/deps/libretro-common/audio/conversion/s16_to_float_neon.c
new file mode 100644 (file)
index 0000000..0972de9
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (s16_to_float_neon.S).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)
+
+#if defined(__thumb__)
+#define DECL_ARMMODE(x) "  .align 2\n" "  .global " x "\n" "  .thumb\n" "  .thumb_func\n" "  .type " x ", %function\n" x ":\n"
+#else
+#define DECL_ARMMODE(x) "  .align 4\n" "  .global " x "\n" "  .arm\n" x ":\n"
+#endif
+
+asm(
+    DECL_ARMMODE("convert_s16_float_asm")
+    DECL_ARMMODE("_convert_s16_float_asm")
+    "# convert_s16_float_asm(float *out, const int16_t *in, size_t samples, const float *gain)\n"
+    "   # Hacky way to get a constant of 2^-15.\n"
+    "   # Might be faster to just load a constant from memory.\n"
+    "   # It's just done once however ...\n"
+    "   vmov.f32 q8, #0.25\n"
+    "   vmul.f32 q8, q8, q8\n"
+    "   vmul.f32 q8, q8, q8\n"
+    "   vmul.f32 q8, q8, q8\n"
+    "   vadd.f32 q8, q8, q8\n"
+    "\n"
+    "   # Apply gain\n"
+    "   vld1.f32 {d6[0]}, [r3]\n"
+    "   vmul.f32 q8, q8, d6[0]\n"
+    "\n"
+    "1:\n"
+    "   # Preload here?\n"
+    "   vld1.s16 {q0}, [r1]!\n"
+    "\n"
+    "   # Widen to 32-bit\n"
+    "   vmovl.s16 q1, d0\n"
+    "   vmovl.s16 q2, d1\n"
+    "\n"
+    "   # Convert to float\n"
+    "   vcvt.f32.s32 q1, q1\n"
+    "   vcvt.f32.s32 q2, q2\n"
+    "\n"
+    "   vmul.f32 q1, q1, q8\n"
+    "   vmul.f32 q2, q2, q8\n"
+    "\n"
+    "   vst1.f32 {q1-q2}, [r0]!\n"
+    "\n"
+    "   # Guaranteed to get samples in multiples of 8.\n"
+    "   subs r2, r2, #8\n"
+    "   bne 1b\n"
+    "\n"
+    "   bx lr\n"
+    "\n"
+    );
+#endif
diff --git a/deps/libretro-common/audio/conversion/stereo_to_mono_float.c b/deps/libretro-common/audio/conversion/stereo_to_mono_float.c
new file mode 100644 (file)
index 0000000..cdec696
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright  (C) 2010-2023 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (mono_to_stereo.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+
+#include <audio/conversion/dual_mono.h>
+
+/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */
+void convert_to_mono_float_left(float *out, const float *in, size_t frames)
+{
+   unsigned i = 0;
+
+   if (!out || !in || !frames)
+      return;
+
+   for (; i < frames; i++)
+   {
+      out[i] = in[i * 2];
+   }
+}
+
+/* Why is there no equivalent for int16_t samples?
+ * No inherent reason, I just didn't need one.
+ * If you do, open a pull request.
+ * Same goes for the lack of a convert_to_mono_float_right;
+ * I didn't need one, so I didn't write one. */
\ No newline at end of file
diff --git a/deps/libretro-common/audio/dsp_filter.c b/deps/libretro-common/audio/dsp_filter.c
new file mode 100644 (file)
index 0000000..544a9fb
--- /dev/null
@@ -0,0 +1,324 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (dsp_filter.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+
+#include <retro_miscellaneous.h>
+
+#include <compat/posix_string.h>
+#include <dynamic/dylib.h>
+
+#include <file/file_path.h>
+#include <file/config_file_userdata.h>
+#include <features/features_cpu.h>
+#include <lists/string_list.h>
+#include <string/stdstring.h>
+#include <libretro_dspfilter.h>
+
+#include <audio/dsp_filter.h>
+
+struct retro_dsp_plug
+{
+#ifdef HAVE_DYLIB
+   dylib_t lib;
+#endif
+   const struct dspfilter_implementation *impl;
+};
+
+struct retro_dsp_instance
+{
+   const struct dspfilter_implementation *impl;
+   void *impl_data;
+};
+
+struct retro_dsp_filter
+{
+   config_file_t *conf;
+
+   struct retro_dsp_plug *plugs;
+   unsigned num_plugs;
+
+   struct retro_dsp_instance *instances;
+   unsigned num_instances;
+};
+
+static const struct dspfilter_implementation *find_implementation(
+      retro_dsp_filter_t *dsp, const char *ident)
+{
+   unsigned i;
+   for (i = 0; i < dsp->num_plugs; i++)
+   {
+      if (string_is_equal(dsp->plugs[i].impl->short_ident, ident))
+         return dsp->plugs[i].impl;
+   }
+
+   return NULL;
+}
+
+static const struct dspfilter_config dspfilter_config = {
+   config_userdata_get_float,
+   config_userdata_get_int,
+   config_userdata_get_float_array,
+   config_userdata_get_int_array,
+   config_userdata_get_string,
+   config_userdata_free,
+};
+
+static bool create_filter_graph(retro_dsp_filter_t *dsp, float sample_rate)
+{
+   unsigned i;
+   struct retro_dsp_instance *instances = NULL;
+   unsigned filters                     = 0;
+
+   if (!config_get_uint(dsp->conf, "filters", &filters))
+      return false;
+
+   instances = (struct retro_dsp_instance*)calloc(filters, sizeof(*instances));
+   if (!instances)
+      return false;
+
+   dsp->instances     = instances;
+   dsp->num_instances = filters;
+
+   for (i = 0; i < filters; i++)
+   {
+      struct config_file_userdata userdata;
+      struct dspfilter_info info;
+      char key[64];
+      char name[64];
+
+      key[0] = name[0] = '\0';
+
+      info.input_rate  = sample_rate;
+
+      snprintf(key, sizeof(key), "filter%u", i);
+
+      if (!config_get_array(dsp->conf, key, name, sizeof(name)))
+         return false;
+
+      dsp->instances[i].impl = find_implementation(dsp, name);
+      if (!dsp->instances[i].impl)
+         return false;
+
+      userdata.conf = dsp->conf;
+      /* Index-specific configs take priority over ident-specific. */
+      userdata.prefix[0] = key;
+      userdata.prefix[1] = dsp->instances[i].impl->short_ident;
+
+      dsp->instances[i].impl_data = dsp->instances[i].impl->init(&info,
+            &dspfilter_config, &userdata);
+      if (!dsp->instances[i].impl_data)
+         return false;
+   }
+
+   return true;
+}
+
+#if defined(HAVE_FILTERS_BUILTIN)
+extern const struct dspfilter_implementation *panning_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
+extern const struct dspfilter_implementation *iir_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
+extern const struct dspfilter_implementation *echo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
+extern const struct dspfilter_implementation *phaser_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
+extern const struct dspfilter_implementation *wahwah_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
+extern const struct dspfilter_implementation *eq_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
+extern const struct dspfilter_implementation *chorus_dspfilter_get_implementation(dspfilter_simd_mask_t mask);
+
+static const dspfilter_get_implementation_t dsp_plugs_builtin[] = {
+   panning_dspfilter_get_implementation,
+   iir_dspfilter_get_implementation,
+   echo_dspfilter_get_implementation,
+   phaser_dspfilter_get_implementation,
+   wahwah_dspfilter_get_implementation,
+   eq_dspfilter_get_implementation,
+   chorus_dspfilter_get_implementation,
+};
+
+static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
+{
+   unsigned i;
+   dspfilter_simd_mask_t mask   = (dspfilter_simd_mask_t)cpu_features_get();
+   struct retro_dsp_plug *plugs = (struct retro_dsp_plug*)
+      calloc(ARRAY_SIZE(dsp_plugs_builtin), sizeof(*plugs));
+
+   if (!plugs)
+      return false;
+
+   dsp->plugs     = plugs;
+   dsp->num_plugs = ARRAY_SIZE(dsp_plugs_builtin);
+
+   for (i = 0; i < ARRAY_SIZE(dsp_plugs_builtin); i++)
+   {
+      dsp->plugs[i].impl = dsp_plugs_builtin[i](mask);
+      if (!dsp->plugs[i].impl)
+         return false;
+   }
+
+   return true;
+}
+#elif defined(HAVE_DYLIB)
+static bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)
+{
+   unsigned i;
+   dspfilter_simd_mask_t mask = (dspfilter_simd_mask_t)cpu_features_get();
+   unsigned list_size         = list ? (unsigned)list->size : 0;
+
+   for (i = 0; i < list_size; i++)
+   {
+      dspfilter_get_implementation_t cb;
+      const struct dspfilter_implementation *impl = NULL;
+      struct retro_dsp_plug *new_plugs            = NULL;
+      dylib_t lib                                 =
+         dylib_load(list->elems[i].data);
+
+      if (!lib)
+         continue;
+
+      cb = (dspfilter_get_implementation_t)dylib_proc(lib, "dspfilter_get_implementation");
+      if (!cb)
+      {
+         dylib_close(lib);
+         continue;
+      }
+
+      impl = cb(mask);
+      if (!impl)
+      {
+         dylib_close(lib);
+         continue;
+      }
+
+      if (impl->api_version != DSPFILTER_API_VERSION)
+      {
+         dylib_close(lib);
+         continue;
+      }
+
+      new_plugs = (struct retro_dsp_plug*)
+         realloc(dsp->plugs, sizeof(*dsp->plugs) * (dsp->num_plugs + 1));
+      if (!new_plugs)
+      {
+         dylib_close(lib);
+         return false;
+      }
+
+      /* Found plug. */
+
+      dsp->plugs = new_plugs;
+      dsp->plugs[dsp->num_plugs].lib = lib;
+      dsp->plugs[dsp->num_plugs].impl = impl;
+      dsp->num_plugs++;
+   }
+
+   return true;
+}
+#endif
+
+retro_dsp_filter_t *retro_dsp_filter_new(
+      const char *filter_config,
+      void *string_data,
+      float sample_rate)
+{
+   config_file_t *conf           = NULL;
+   struct string_list *plugs     = NULL;
+   retro_dsp_filter_t *dsp       = (retro_dsp_filter_t*)calloc(1, sizeof(*dsp));
+
+   if (!dsp)
+      return NULL;
+
+   if (!(conf = config_file_new_from_path_to_string(filter_config)))
+      goto error;
+
+   dsp->conf = conf;
+
+   if (string_data)
+      plugs = (struct string_list*)string_data;
+
+#if defined(HAVE_DYLIB) || defined(HAVE_FILTERS_BUILTIN)
+   if (!append_plugs(dsp, plugs))
+      goto error;
+#endif
+
+   if (plugs)
+      string_list_free(plugs);
+   plugs = NULL;
+
+   if (!create_filter_graph(dsp, sample_rate))
+      goto error;
+
+   return dsp;
+
+error:
+   if (plugs)
+      string_list_free(plugs);
+   retro_dsp_filter_free(dsp);
+   return NULL;
+}
+
+void retro_dsp_filter_free(retro_dsp_filter_t *dsp)
+{
+   unsigned i;
+   if (!dsp)
+      return;
+
+   for (i = 0; i < dsp->num_instances; i++)
+   {
+      if (dsp->instances[i].impl_data && dsp->instances[i].impl)
+         dsp->instances[i].impl->free(dsp->instances[i].impl_data);
+   }
+   free(dsp->instances);
+
+#ifdef HAVE_DYLIB
+   for (i = 0; i < dsp->num_plugs; i++)
+   {
+      if (dsp->plugs[i].lib)
+         dylib_close(dsp->plugs[i].lib);
+   }
+   free(dsp->plugs);
+#endif
+
+   if (dsp->conf)
+      config_file_free(dsp->conf);
+
+   free(dsp);
+}
+
+void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
+      struct retro_dsp_data *data)
+{
+   unsigned i;
+   struct dspfilter_output output = {0};
+   struct dspfilter_input input   = {0};
+
+   output.samples = data->input;
+   output.frames  = data->input_frames;
+
+   for (i = 0; i < dsp->num_instances; i++)
+   {
+      input.samples = output.samples;
+      input.frames  = output.frames;
+      dsp->instances[i].impl->process(
+            dsp->instances[i].impl_data, &output, &input);
+   }
+
+   data->output        = output.samples;
+   data->output_frames = output.frames;
+}
diff --git a/deps/libretro-common/audio/dsp_filters/BassBoost.dsp b/deps/libretro-common/audio/dsp_filters/BassBoost.dsp
new file mode 100644 (file)
index 0000000..e903e24
--- /dev/null
@@ -0,0 +1,11 @@
+filters = 2
+filter0 = iir
+filter1 = panning
+
+iir_gain = 10.0
+iir_type = BBOOST
+iir_frequency = 200.0
+
+# Avoids clipping.
+panning_left_mix = "0.3 0.0"
+panning_right_mix = "0.0 0.3"
diff --git a/deps/libretro-common/audio/dsp_filters/ChipTune-Lowpass.dsp b/deps/libretro-common/audio/dsp_filters/ChipTune-Lowpass.dsp
new file mode 100644 (file)
index 0000000..0652922
--- /dev/null
@@ -0,0 +1,7 @@
+filters = 1
+filter0 = iir
+
+iir_frequency = 8600.0
+iir_quality = 0.707
+iir_gain = 6.0
+iir_type = LPF
diff --git a/deps/libretro-common/audio/dsp_filters/ChipTuneEnhance.dsp b/deps/libretro-common/audio/dsp_filters/ChipTuneEnhance.dsp
new file mode 100644 (file)
index 0000000..41b2775
--- /dev/null
@@ -0,0 +1,22 @@
+filters = 4
+filter0 = eq
+filter1 = reverb
+filter2 = iir
+filter3 = panning
+
+eq_frequencies = "32 64 125 250 500 1000 2000 4000 8000 16000 20000"
+eq_gains = "6 9 12 7 6 5 7 9 11 6 0"
+
+# Reverb - slight reverb
+ reverb_drytime = 0.5
+ reverb_wettime = 0.15
+ reverb_damping = 0.8
+ reverb_roomwidth = 0.25
+ reverb_roomsize = 0.25
+
+# IIR - filters out some harsh sounds on the upper end
+iir_type = RIAA_CD
+
+# Panning - cut the volume a bit
+panning_left_mix = "0.75 0.0"
+panning_right_mix = "0.0 0.75"
diff --git a/deps/libretro-common/audio/dsp_filters/Chorus.dsp b/deps/libretro-common/audio/dsp_filters/Chorus.dsp
new file mode 100644 (file)
index 0000000..f48b3c3
--- /dev/null
@@ -0,0 +1,14 @@
+filters = 1
+filter0 = chorus
+
+# Controls the base delay of the chorus (milliseconds).
+# chorus_delay_ms = 25.0
+#
+# Controls the depth of the delay. The delay will vary between delay_ms +/- depth_ms.
+# chorus_depth_ms = 1.0
+#
+# Frequency of LFO which controls delay.
+# chorus_lfo_freq = 0.5
+#
+# Controls dry/wet-ness of effect. 1.0 = full chorus, 0.0 = no chorus.
+# chorus_drywet = 0.8
diff --git a/deps/libretro-common/audio/dsp_filters/Crystalizer.dsp b/deps/libretro-common/audio/dsp_filters/Crystalizer.dsp
new file mode 100644 (file)
index 0000000..f8fceb5
--- /dev/null
@@ -0,0 +1,4 @@
+filters = 1
+filter0 = crystalizer
+# Controls dry/wet-ness of effect. 0.0 = none, 10.0 = max.
+crystalizer_intensity = 5.0
diff --git a/deps/libretro-common/audio/dsp_filters/EQ.dsp b/deps/libretro-common/audio/dsp_filters/EQ.dsp
new file mode 100644 (file)
index 0000000..5a69a68
--- /dev/null
@@ -0,0 +1,41 @@
+filters = 1
+filter0 = eq
+
+# Defaults
+
+# Beta factor for Kaiser window.
+# Lower values will allow better frequency resolution, but more ripple.
+# eq_window_beta = 4.0
+
+# The block size on which FFT is done.
+# Too high value requires more processing as well as longer latency but
+# allows finer-grained control over the spectrum.
+# eq_block_size_log2 = 8
+
+# An array of which frequencies to control.
+# You can create an arbitrary amount of these sampling points.
+# The EQ will try to create a frequency response which fits well to these points.
+# The filter response is linearly interpolated between sampling points here.
+#
+# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
+# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
+#
+# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
+# eq_frequencies = "500 1000 2000"
+# eq_gains = "0 3 0"
+# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.
+
+# By default, this filter has a flat frequency response.
+
+# Dumps the impulse response generated by the EQ as a plain-text file
+# with one coefficient per line.
+# eq_impulse_response_output = "eq_impulse.txt"
+#
+# Using GNU Octave or Matlab, you can plot the response with:
+#
+# f = fopen('/path/to/eq_impulse.txt');
+# l = textscan(f, '%f');
+# res = l{1};
+# freqz(res, 1, 4096, 48000);
+#
+# It will give the response in Hz; 48000 is the default Output Rate of RetroArch
diff --git a/deps/libretro-common/audio/dsp_filters/Echo.dsp b/deps/libretro-common/audio/dsp_filters/Echo.dsp
new file mode 100644 (file)
index 0000000..b92bdcc
--- /dev/null
@@ -0,0 +1,19 @@
+filters = 1
+filter0 = echo
+
+# Somewhat fancy Echo filter. Can take any number of echo channels with varying delays (ms) and feedback factors.
+# Echo output from all channels can be fed back into each other to create a somewhat reverb-like effect if desired.
+
+# Defaults, 200 ms delay echo with feedback:
+# Delay in ms. Takes an array with multiple channels.
+# echo_delay = "200"
+# Feedback factor for echo.
+# echo_feedback = "0.5"
+# Overall echo amplification. If too high, the echo becomes unstable due to feedback.
+# echo_amp = "0.2"
+
+# Reverby preset.
+# echo_delay    = " 60  80 120 172 200 320 380"
+# echo_feedback = "0.5 0.5 0.4 0.3 0.5 0.3 0.2"
+
+# echo_amp = "0.12"
diff --git a/deps/libretro-common/audio/dsp_filters/EchoReverb.dsp b/deps/libretro-common/audio/dsp_filters/EchoReverb.dsp
new file mode 100644 (file)
index 0000000..502effe
--- /dev/null
@@ -0,0 +1,12 @@
+filters = 2
+filter0 = echo
+filter1 = reverb
+
+echo_delay = "200"
+echo_feedback = "0.6"
+echo_amp = "0.25"
+
+reverb_roomwidth = 0.75
+reverb_roomsize = 0.75
+reverb_damping = 1.0
+reverb_wettime = 0.3
diff --git a/deps/libretro-common/audio/dsp_filters/HighShelfDampen.dsp b/deps/libretro-common/audio/dsp_filters/HighShelfDampen.dsp
new file mode 100644 (file)
index 0000000..e5a3628
--- /dev/null
@@ -0,0 +1,6 @@
+filters = 1
+filter0 = iir
+
+iir_gain = -12.0
+iir_type = HSH
+iir_frequency = 8000.0
diff --git a/deps/libretro-common/audio/dsp_filters/IIR.dsp b/deps/libretro-common/audio/dsp_filters/IIR.dsp
new file mode 100644 (file)
index 0000000..ecad4cf
--- /dev/null
@@ -0,0 +1,22 @@
+filters = 1
+filter0 = iir
+
+# Defaults.
+#iir_frequency = 1024.0
+#iir_quality = 0.707
+#iir_gain = 0.0
+#iir_type = LPF
+
+# Filter types:
+# LPF: Low-pass
+# HPF: High-pass
+# BPCSGF: Band-pass #1
+# BPZPGF: Band-pass #2
+# APF: Allpass
+# NOTCH: Notch filter
+# RIAA_phono: RIAA record/tape deemphasis
+# PEQ: peaking band EQ
+# BBOOST: Bassboost
+# LSH: Low-shelf
+# HSH: High-shelf
+# RIAA_CD: CD de-emphasis
diff --git a/deps/libretro-common/audio/dsp_filters/LowPassCPS.dsp b/deps/libretro-common/audio/dsp_filters/LowPassCPS.dsp
new file mode 100644 (file)
index 0000000..ae42e15
--- /dev/null
@@ -0,0 +1,47 @@
+filters = 1
+filter0 = eq
+
+eq_frequencies = "8000 10000 12500 16000 20000"
+eq_gains = "0 -30 -30 -30 -30"
+
+# Low pass filter for the QSound chip from CPS-1/2.
+# Some games have aliasing due low quality samples, so you can hear some annoying noisy near 11 kHz
+
+# Defaults
+
+# Beta factor for Kaiser window.
+# Lower values will allow better frequency resolution, but more ripple.
+# eq_window_beta = 4.0
+
+# The block size on which FFT is done.
+# Too high value requires more processing as well as longer latency but
+# allows finer-grained control over the spectrum.
+# eq_block_size_log2 = 8
+
+# An array of which frequencies to control.
+# You can create an arbitrary amount of these sampling points.
+# The EQ will try to create a frequency response which fits well to these points.
+# The filter response is linearly interpolated between sampling points here.
+#
+# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.
+# If you want a "peak" in the spectrum or similar, you have to define close points to say, 0 dB.
+#
+# E.g.: A boost of 3 dB at 1 kHz can be expressed as.
+# eq_frequencies = "500 1000 2000"
+# eq_gains = "0 3 0"
+# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.
+
+# By default, this filter has a low pass response with cuttof frequency at ~8600 Hz.
+
+# Dumps the impulse response generated by the EQ as a plain-text file
+# with one coefficient per line.
+# eq_impulse_response_output = "eq_impulse.txt"
+#
+# Using GNU Octave or Matlab, you can plot the response with:
+#
+# f = fopen('/path/to/eq_impulse.txt');
+# l = textscan(f, '%f');
+# res = l{1};
+# freqz(res, 1, 4096, 48000);
+#
+# It will give the response in Hz; 48000 is the default Output Rate of RetroArch
diff --git a/deps/libretro-common/audio/dsp_filters/Makefile b/deps/libretro-common/audio/dsp_filters/Makefile
new file mode 100644 (file)
index 0000000..34392e1
--- /dev/null
@@ -0,0 +1,135 @@
+compiler    := gcc
+extra_flags :=
+use_neon    := 0
+build       = release
+DYLIB        := so
+PREFIX      := /usr
+INSTALLDIR  := $(PREFIX)/lib/retroarch/filters/audio
+
+ifeq ($(platform),)
+   platform = unix
+   ifeq ($(shell uname -s),)
+      platform = win
+   else ifneq ($(findstring Darwin,$(shell uname -s)),)
+      platform = osx
+      arch     = intel
+      ifeq ($(shell uname -p),powerpc)
+         arch = ppc
+      endif
+   else ifneq ($(findstring MINGW,$(shell uname -s)),)
+      platform = win
+   endif
+endif
+
+ifeq ($(platform),gcc)
+   extra_rules_gcc := $(shell $(compiler) -dumpmachine)
+endif
+
+ifneq (,$(findstring armv7,$(extra_rules_gcc)))
+   extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon
+   use_neon := 1
+endif
+
+ifneq (,$(findstring hardfloat,$(extra_rules_gcc)))
+   extra_flags += -mfloat-abi=hard
+endif
+
+ifeq (release,$(build))
+   extra_flags += -O2
+endif
+
+ifeq (debug,$(build))
+   extra_flags += -O0 -g
+endif
+
+ldflags := $(LDFLAGS) -shared -lm -Wl,--version-script=link.T
+
+ifeq ($(platform), unix)
+   DYLIB = so
+else ifeq ($(platform), osx)
+   compiler := $(CC)
+   DYLIB = dylib
+   ldflags := -dynamiclib
+   ARCHFLAGS=
+   MINVERFLAGS=
+   ifeq ($(shell uname -p),arm)
+      MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)
+   else ifeq ($(HAVE_METAL),1)
+      MINVERFLAGS = -mmacosx-version-min=10.13 -stdlib=libc++  # macOS  (Metal, x86 64bit)
+   else ifeq ($(shell uname -p),powerpc)
+      MINVERFLAGS = -mmacosx-version-min=10.5  # macOSX (PowerPC 32-bit)
+   else ifeq ($(shell uname -m),i386)
+      MINVERFLAGS = -mmacosx-version-min=10.6  # macOSX (OpenGL, x86 32bit)
+   else
+      MINVERFLAGS = -mmacosx-version-min=10.7 -stdlib=libc++ # macOSX (OpenGL, x86 64bit)
+   endif
+
+       # Build for a specific architecture when ARCH is defined as a switch
+   ifeq ($(ARCH),arm64)
+      MINVERFLAGS  = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)
+      ARCHFLAGS    = -arch arm64
+   else ifeq ($(ARCH),x86_64)
+      ifeq ($(HAVE_METAL),1)
+         MINVERFLAGS  = -mmacosx-version-min=10.13 -stdlib=libc++
+      else
+         MINVERFLAGS  = -mmacosx-version-min=10.7  -stdlib=libc++
+      endif
+      ARCHFLAGS       = -arch x86_64
+   else ifeq ($(ARCH),x86)
+      MINVERFLAGS     = -mmacosx-version-min=10.6
+      ARCHFLAGS       = -arch x86
+   else ifeq ($(ARCH),ppc)
+      MINVERFLAGS     = -mmacosx-version-min=10.5
+      ARCHFLAGS       = -arch ppc
+   endif
+   ifeq ($(BUILDBOT),1)
+      ARCHFLAGS       = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT)
+   endif
+       extraflags += $(MINVERFLAGS) $(ARCHFLAGS)
+       ldflags += $(MINVERFLAGS) $(ARCHFLAGS)
+else
+   extra_flags += -static-libgcc -static-libstdc++
+   DYLIB = dll
+endif
+
+CC      := $(compiler) -Wall
+CXX     := $(subst CC,++,$(compiler)) -std=gnu++0x -Wall
+flags   := $(CPPFLAGS) $(CFLAGS) -fPIC $(extra_flags) -I../../include
+asflags := $(ASFLAGS) -fPIC  $(extra_flags)
+objects :=
+
+ifeq (1,$(use_neon))
+   ASMFLAGS := -INEON/asm
+   asflags += -mfpu=neon
+endif
+
+plugs := $(wildcard *.c)
+objects := $(plugs:.c=.o)
+targets := $(objects:.o=.$(DYLIB))
+
+all: build;
+
+%.o: %.S
+       $(CC) -c -o $@ $(asflags)  $(ASMFLAGS)  $<
+
+%.o: %.c
+       $(CC) -c -o $@ $(flags) $<
+
+%.$(DYLIB): %.o
+       $(CC) -o $@ $(ldflags) $(flags) $^
+
+build: $(targets)
+
+clean:
+       rm -f *.o
+       rm -f *.$(DYLIB)
+
+strip:
+       strip -s *.$(DYLIB)
+
+install:
+       mkdir -p $(DESTDIR)$(INSTALLDIR)
+       cp -t $(DESTDIR)$(INSTALLDIR) $(targets) *.dsp
+
+test-install:
+       DESTDIR=/tmp/build $(MAKE) install
diff --git a/deps/libretro-common/audio/dsp_filters/Mono.dsp b/deps/libretro-common/audio/dsp_filters/Mono.dsp
new file mode 100644 (file)
index 0000000..bef96cf
--- /dev/null
@@ -0,0 +1,12 @@
+filters = 1
+filter0 = panning
+
+# Gains are linear.
+
+# Stereo Mono:
+ panning_left_mix = "0.5 0.5"
+ panning_right_mix = "0.5 0.5"
+
+# Mono on one speaker:
+# panning_left_mix = "0.5 0.5"
+# panning_right_mix = "0.0 0.0"
diff --git a/deps/libretro-common/audio/dsp_filters/Panning.dsp b/deps/libretro-common/audio/dsp_filters/Panning.dsp
new file mode 100644 (file)
index 0000000..5b38f62
--- /dev/null
@@ -0,0 +1,22 @@
+filters = 1
+filter0 = panning
+
+# Gains are linear.
+
+# The default. Left and right channels map to each other.
+panning_left_mix = "1.0 0.0"
+panning_right_mix = "0.0 1.0"
+
+# Some examples:
+#
+# Mono:
+# panning_left_mix = "0.5 0.5"
+# panning_right_mix = "0.5 0.5"
+
+# Swap left and right channels:
+# panning_left_mix = "0.0 1.0"
+# panning_right_mix = "1.0 0.0"
+#
+# Mono on one speaker:
+# panning_left_mix = "0.5 0.5"
+# panning_right_mix = "0.0 0.0"
diff --git a/deps/libretro-common/audio/dsp_filters/Phaser.dsp b/deps/libretro-common/audio/dsp_filters/Phaser.dsp
new file mode 100644 (file)
index 0000000..effd48f
--- /dev/null
@@ -0,0 +1,10 @@
+filters = 1
+filter0 = phaser
+
+# Defaults.
+# phaser_lfo_freq = 0.4
+# phaser_lfo_start_phase = 0.0
+# phaser_feedback = 0.0
+# phaser_depth = 0.4
+# phaser_dry_wet = 0.5
+# phaser_stages = 2
diff --git a/deps/libretro-common/audio/dsp_filters/Reverb.dsp b/deps/libretro-common/audio/dsp_filters/Reverb.dsp
new file mode 100644 (file)
index 0000000..d4af139
--- /dev/null
@@ -0,0 +1,9 @@
+filters = 1
+filter0 = reverb
+
+# Defaults.
+# reverb_drytime = 0.43
+# reverb_wettime = 0.4
+# reverb_damping = 0.8
+# reverb_roomwidth = 0.56
+# reverb_roomsize = 0.56
diff --git a/deps/libretro-common/audio/dsp_filters/Tremolo.dsp b/deps/libretro-common/audio/dsp_filters/Tremolo.dsp
new file mode 100644 (file)
index 0000000..90abdd7
--- /dev/null
@@ -0,0 +1,6 @@
+filters = 1
+filter0 = tremolo
+
+# Defaults.
+#tremolo_frequency = 4.0
+#tremolo_depth = 0.9
diff --git a/deps/libretro-common/audio/dsp_filters/Vibrato.dsp b/deps/libretro-common/audio/dsp_filters/Vibrato.dsp
new file mode 100644 (file)
index 0000000..0ad42a4
--- /dev/null
@@ -0,0 +1,6 @@
+filters = 1
+filter0 = vibrato
+
+# Defaults.
+#vibrato_frequency = 5.0
+#vibrato_depth = 0.5
diff --git a/deps/libretro-common/audio/dsp_filters/WahWah.dsp b/deps/libretro-common/audio/dsp_filters/WahWah.dsp
new file mode 100644 (file)
index 0000000..41adb2f
--- /dev/null
@@ -0,0 +1,9 @@
+filters = 1
+filter0 = wahwah
+
+# Defaults.
+# wahwah_lfo_freq = 1.5
+# wahwah_lfo_start_phase = 0.0
+# wahwah_freq_offset = 0.3
+# wahwah_depth = 0.7
+# wahwah_resonance = 2.5
diff --git a/deps/libretro-common/audio/dsp_filters/chorus.c b/deps/libretro-common/audio/dsp_filters/chorus.c
new file mode 100644 (file)
index 0000000..c6dae11
--- /dev/null
@@ -0,0 +1,155 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (chorus.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+
+#define CHORUS_MAX_DELAY 4096
+#define CHORUS_DELAY_MASK (CHORUS_MAX_DELAY - 1)
+
+struct chorus_data
+{
+   float old[2][CHORUS_MAX_DELAY];
+   float delay;
+   float depth;
+   float input_rate;
+   float mix_dry;
+   float mix_wet;
+   unsigned old_ptr;
+   unsigned lfo_ptr;
+   unsigned lfo_period;
+};
+
+static void chorus_free(void *data)
+{
+   if (data)
+      free(data);
+}
+
+static void chorus_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i;
+   float *out             = NULL;
+   struct chorus_data *ch = (struct chorus_data*)data;
+
+   output->samples        = input->samples;
+   output->frames         = input->frames;
+   out                    = output->samples;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      unsigned delay_int;
+      float delay_frac, l_a, l_b, r_a, r_b;
+      float chorus_l, chorus_r;
+      float in[2]             = { out[0], out[1] };
+      float delay             = ch->delay + ch->depth * sin((2.0 * M_PI * ch->lfo_ptr++) / ch->lfo_period);
+
+      delay                  *= ch->input_rate;
+      if (ch->lfo_ptr >= ch->lfo_period)
+         ch->lfo_ptr          = 0;
+
+      delay_int               = (unsigned)delay;
+
+      if (delay_int >= CHORUS_MAX_DELAY - 1)
+         delay_int            = CHORUS_MAX_DELAY - 2;
+
+      delay_frac              = delay - delay_int;
+
+      ch->old[0][ch->old_ptr] = in[0];
+      ch->old[1][ch->old_ptr] = in[1];
+
+      l_a                     = ch->old[0][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];
+      l_b                     = ch->old[0][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];
+      r_a                     = ch->old[1][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];
+      r_b                     = ch->old[1][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];
+
+      /* Lerp introduces aliasing of the chorus component,
+       * but doing full polyphase here is probably overkill. */
+      chorus_l                = l_a * (1.0f - delay_frac) + l_b * delay_frac;
+      chorus_r                = r_a * (1.0f - delay_frac) + r_b * delay_frac;
+
+      out[0]                  = ch->mix_dry * in[0] + ch->mix_wet * chorus_l;
+      out[1]                  = ch->mix_dry * in[1] + ch->mix_wet * chorus_r;
+
+      ch->old_ptr             = (ch->old_ptr + 1) & CHORUS_DELAY_MASK;
+   }
+}
+
+static void *chorus_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   float delay, depth, lfo_freq, drywet;
+   struct chorus_data *ch = (struct chorus_data*)calloc(1, sizeof(*ch));
+   if (!ch)
+      return NULL;
+
+   config->get_float(userdata, "delay_ms", &delay, 25.0f);
+   config->get_float(userdata, "depth_ms", &depth, 1.0f);
+   config->get_float(userdata, "lfo_freq", &lfo_freq, 0.5f);
+   config->get_float(userdata, "drywet", &drywet, 0.8f);
+
+   delay            /= 1000.0f;
+   depth            /= 1000.0f;
+
+   if (depth > delay)
+      depth          = delay;
+
+   if (drywet < 0.0f)
+      drywet         = 0.0f;
+   else if (drywet > 1.0f)
+      drywet         = 1.0f;
+
+   ch->mix_dry       = 1.0f - 0.5f * drywet;
+   ch->mix_wet       = 0.5f * drywet;
+
+   ch->delay         = delay;
+   ch->depth         = depth;
+   ch->lfo_period    = (1.0f / lfo_freq) * info->input_rate;
+   ch->input_rate    = info->input_rate;
+   if (!ch->lfo_period)
+      ch->lfo_period = 1;
+   return ch;
+}
+
+static const struct dspfilter_implementation chorus_plug = {
+   chorus_init,
+   chorus_process,
+   chorus_free,
+
+   DSPFILTER_API_VERSION,
+   "Chorus",
+   "chorus",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation chorus_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *
+dspfilter_get_implementation(dspfilter_simd_mask_t mask) { return &chorus_plug; }
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/configure b/deps/libretro-common/audio/dsp_filters/configure
new file mode 100755 (executable)
index 0000000..9e1e55d
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+PACKAGE_NAME=retroarch-filters-audio
\ No newline at end of file
diff --git a/deps/libretro-common/audio/dsp_filters/crystalizer.c b/deps/libretro-common/audio/dsp_filters/crystalizer.c
new file mode 100644 (file)
index 0000000..8ccecd8
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (echo.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+
+struct delta_data
+{
+   float intensity;
+   float old[2];
+};
+
+static void delta_free(void *data)
+{
+   free(data);
+}
+
+static void delta_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i, c;
+   struct delta_data *d   = (struct delta_data*)data;
+   float *out             = output->samples;
+   output->samples        = input->samples;
+   output->frames         = input->frames;
+
+   for (i = 0; i < input->frames; i++)
+   {
+      for (c = 0; c < 2; c++)
+      {
+           float current  = *out;
+           *out++         = current + (current - d->old[c]) * d->intensity;
+           d->old[c]      = current;
+      }
+   }
+}
+
+static void *delta_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   struct delta_data *d = (struct delta_data*)calloc(1, sizeof(*d));
+   if (!d)
+      return NULL;
+   config->get_float(userdata, "intensity", &d->intensity, 5.0f);
+   return d;
+}
+
+static const struct dspfilter_implementation delta_plug = {
+   delta_init,
+   delta_process,
+   delta_free,
+   DSPFILTER_API_VERSION,
+   "Delta Sharpening",
+   "crystalizer",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation delta_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &delta_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/echo.c b/deps/libretro-common/audio/dsp_filters/echo.c
new file mode 100644 (file)
index 0000000..27df905
--- /dev/null
@@ -0,0 +1,176 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (echo.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+
+struct echo_channel
+{
+   float *buffer;
+   unsigned ptr;
+   unsigned frames;
+   float feedback;
+};
+
+struct echo_data
+{
+   struct echo_channel *channels;
+   unsigned num_channels;
+   float amp;
+};
+
+static void echo_free(void *data)
+{
+   unsigned i;
+   struct echo_data *echo = (struct echo_data*)data;
+
+   for (i = 0; i < echo->num_channels; i++)
+      free(echo->channels[i].buffer);
+   free(echo->channels);
+   free(echo);
+}
+
+static void echo_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i, c;
+   float *out             = NULL;
+   struct echo_data *echo = (struct echo_data*)data;
+
+   output->samples        = input->samples;
+   output->frames         = input->frames;
+
+   out                    = output->samples;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float left, right;
+      float echo_left  = 0.0f;
+      float echo_right = 0.0f;
+
+      for (c = 0; c < echo->num_channels; c++)
+      {
+         echo_left  += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0];
+         echo_right += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1];
+      }
+
+      echo_left     *= echo->amp;
+      echo_right    *= echo->amp;
+
+      left           = out[0] + echo_left;
+      right          = out[1] + echo_right;
+
+      for (c = 0; c < echo->num_channels; c++)
+      {
+         float feedback_left  = out[0] + echo->channels[c].feedback * echo_left;
+         float feedback_right = out[1] + echo->channels[c].feedback * echo_right;
+
+         echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0] = feedback_left;
+         echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1] = feedback_right;
+
+         echo->channels[c].ptr = (echo->channels[c].ptr + 1) % echo->channels[c].frames;
+      }
+
+      out[0] = left;
+      out[1] = right;
+   }
+}
+
+static void *echo_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   unsigned i, channels;
+   struct echo_channel *echo_channels    = NULL;
+   float *delay                          = NULL;
+   float *feedback                       = NULL;
+   unsigned num_delay                    = 0;
+   unsigned num_feedback                 = 0;
+
+   static const float default_delay[]    = { 200.0f };
+   static const float default_feedback[] = { 0.5f };
+   struct echo_data *echo                = (struct echo_data*)
+      calloc(1, sizeof(*echo));
+
+   if (!echo)
+      return NULL;
+
+   config->get_float_array(userdata, "delay", &delay,
+         &num_delay, default_delay, 1);
+   config->get_float_array(userdata, "feedback", &feedback,
+         &num_feedback, default_feedback, 1);
+   config->get_float(userdata, "amp", &echo->amp, 0.2f);
+
+   channels            = num_feedback = num_delay = MIN(num_delay, num_feedback);
+
+   if (!(echo_channels = (struct echo_channel*)calloc(channels,
+         sizeof(*echo_channels))))
+      goto error;
+
+   echo->channels      = echo_channels;
+   echo->num_channels  = channels;
+
+   for (i = 0; i < channels; i++)
+   {
+      unsigned frames  = (unsigned)(delay[i] * info->input_rate / 1000.0f + 0.5f);
+      if (!frames)
+         goto error;
+
+      if (!(echo->channels[i].buffer = (float*)calloc(frames, 2 * sizeof(float))))
+         goto error;
+
+      echo->channels[i].frames   = frames;
+      echo->channels[i].feedback = feedback[i];
+   }
+
+   config->free(delay);
+   config->free(feedback);
+   return echo;
+
+error:
+   config->free(delay);
+   config->free(feedback);
+   echo_free(echo);
+   return NULL;
+}
+
+static const struct dspfilter_implementation echo_plug = {
+   echo_init,
+   echo_process,
+   echo_free,
+
+   DSPFILTER_API_VERSION,
+   "Multi-Echo",
+   "echo",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation echo_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &echo_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/eq.c b/deps/libretro-common/audio/dsp_filters/eq.c
new file mode 100644 (file)
index 0000000..a7578d9
--- /dev/null
@@ -0,0 +1,348 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (eq.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_inline.h>
+#include <retro_miscellaneous.h>
+#include <filters.h>
+#include <libretro_dspfilter.h>
+
+#include "fft/fft.c"
+
+struct eq_data
+{
+   fft_t *fft;
+   float *save;
+   float *block;
+   fft_complex_t *filter;
+   fft_complex_t *fftblock;
+   float buffer[8 * 1024];
+   unsigned block_size;
+   unsigned block_ptr;
+};
+
+struct eq_gain
+{
+   float freq;
+   float gain; /* Linear. */
+};
+
+static void eq_free(void *data)
+{
+   struct eq_data *eq = (struct eq_data*)data;
+   if (!eq)
+      return;
+
+   fft_free(eq->fft);
+   free(eq->save);
+   free(eq->block);
+   free(eq->fftblock);
+   free(eq->filter);
+   free(eq);
+}
+
+static void eq_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   float *out;
+   const float *in;
+   unsigned input_frames;
+   struct eq_data *eq = (struct eq_data*)data;
+
+   output->samples    = eq->buffer;
+   output->frames     = 0;
+
+   out                = eq->buffer;
+   in                 = input->samples;
+   input_frames       = input->frames;
+
+   while (input_frames)
+   {
+      unsigned write_avail = eq->block_size - eq->block_ptr;
+
+      if (input_frames < write_avail)
+         write_avail = input_frames;
+
+      memcpy(eq->block + eq->block_ptr * 2, in, write_avail * 2 * sizeof(float));
+
+      in            += write_avail * 2;
+      input_frames  -= write_avail;
+      eq->block_ptr += write_avail;
+
+      /* Convolve a new block. */
+      if (eq->block_ptr == eq->block_size)
+      {
+         unsigned i, c;
+
+         for (c = 0; c < 2; c++)
+         {
+            fft_process_forward(eq->fft, eq->fftblock, eq->block + c, 2);
+            for (i = 0; i < 2 * eq->block_size; i++)
+               eq->fftblock[i] = fft_complex_mul(eq->fftblock[i], eq->filter[i]);
+            fft_process_inverse(eq->fft, out + c, eq->fftblock, 2);
+         }
+
+         /* Overlap add method, so add in saved block now. */
+         for (i = 0; i < 2 * eq->block_size; i++)
+            out[i]      += eq->save[i];
+
+         /* Save block for later. */
+         memcpy(eq->save, out + 2 * eq->block_size, 2 * eq->block_size * sizeof(float));
+
+         out            += eq->block_size * 2;
+         output->frames += eq->block_size;
+         eq->block_ptr   = 0;
+      }
+   }
+}
+
+static int gains_cmp(const void *a_, const void *b_)
+{
+   const struct eq_gain *a = (const struct eq_gain*)a_;
+   const struct eq_gain *b = (const struct eq_gain*)b_;
+   if (a->freq < b->freq)
+      return -1;
+   if (a->freq > b->freq)
+      return 1;
+   return 0;
+}
+
+static void generate_response(fft_complex_t *response,
+      const struct eq_gain *gains, unsigned num_gains, unsigned samples)
+{
+   unsigned i;
+
+   float start_freq = 0.0f;
+   float start_gain = 1.0f;
+
+   float end_freq   = 1.0f;
+   float end_gain   = 1.0f;
+
+   if (num_gains)
+   {
+      end_freq = gains->freq;
+      end_gain = gains->gain;
+      num_gains--;
+      gains++;
+   }
+
+   /* Create a response by linear interpolation between
+    * known frequency sample points. */
+   for (i = 0; i <= samples; i++)
+   {
+      float gain;
+      float lerp = 0.5f;
+      float freq = (float)i / samples;
+
+      while (freq >= end_freq)
+      {
+         if (num_gains)
+         {
+            start_freq = end_freq;
+            start_gain = end_gain;
+            end_freq = gains->freq;
+            end_gain = gains->gain;
+
+            gains++;
+            num_gains--;
+         }
+         else
+         {
+            start_freq = end_freq;
+            start_gain = end_gain;
+            end_freq = 1.0f;
+            end_gain = 1.0f;
+            break;
+         }
+      }
+
+      /* Edge case where i == samples. */
+      if (end_freq > start_freq)
+         lerp = (freq - start_freq) / (end_freq - start_freq);
+      gain = (1.0f - lerp) * start_gain + lerp * end_gain;
+
+      response[i].real               = gain;
+      response[i].imag               = 0.0f;
+      response[2 * samples - i].real = gain;
+      response[2 * samples - i].imag = 0.0f;
+   }
+}
+
+static void create_filter(struct eq_data *eq, unsigned size_log2,
+      struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)
+{
+   int i;
+   int half_block_size = eq->block_size >> 1;
+   double window_mod   = 1.0 / kaiser_window_function(0.0, beta);
+   fft_t *fft          = fft_new(size_log2);
+   float *time_filter  = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter));
+   if (!fft || !time_filter)
+      goto end;
+
+   /* Make sure bands are in correct order. */
+   qsort(gains, num_gains, sizeof(*gains), gains_cmp);
+
+   /* Compute desired filter response. */
+   generate_response(eq->filter, gains, num_gains, half_block_size);
+
+   /* Get equivalent time-domain filter. */
+   fft_process_inverse(fft, time_filter, eq->filter, 1);
+
+   /* ifftshift() to create the correct linear phase filter.
+    * The filter response was designed with zero phase, which
+    * won't work unless we compensate
+    * for the repeating property of the FFT here
+    * by flipping left and right blocks. */
+   for (i = 0; i < half_block_size; i++)
+   {
+      float tmp = time_filter[i + half_block_size];
+      time_filter[i + half_block_size] = time_filter[i];
+      time_filter[i] = tmp;
+   }
+
+   /* Apply a window to smooth out the frequency repsonse. */
+   for (i = 0; i < (int)eq->block_size; i++)
+   {
+      /* Kaiser window. */
+      double phase    = (double)i / eq->block_size;
+      phase           = 2.0 * (phase - 0.5);
+      time_filter[i] *= window_mod * kaiser_window_function(phase, beta);
+   }
+
+#ifdef DEBUG
+   /* Debugging. */
+   if (filter_path)
+   {
+      FILE *file = fopen(filter_path, "w");
+      if (file)
+      {
+         for (i = 0; i < (int)eq->block_size - 1; i++)
+            fprintf(file, "%.8f\n", time_filter[i + 1]);
+         fclose(file);
+      }
+   }
+#endif
+
+   /* Padded FFT to create our FFT filter.
+    * Make our even-length filter odd by discarding the first coefficient.
+    * For some interesting reason, this allows us to design an odd-length linear phase filter.
+    */
+   fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1);
+
+end:
+   fft_free(fft);
+   free(time_filter);
+}
+
+static void *eq_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   int size_log2;
+   float beta;
+   float *frequencies, *gain;
+   unsigned num_freq, num_gain, i, size;
+   struct eq_gain *gains      = NULL;
+   char *filter_path          = NULL;
+   const float default_freq[] = { 0.0f, info->input_rate };
+   const float default_gain[] = { 0.0f, 0.0f };
+   struct eq_data *eq         = (struct eq_data*)calloc(1, sizeof(*eq));
+   if (!eq)
+      return NULL;
+
+   config->get_float(userdata, "window_beta", &beta, 4.0f);
+
+   config->get_int(userdata, "block_size_log2", &size_log2, 8);
+   size = 1 << size_log2;
+
+   config->get_float_array(userdata, "frequencies", &frequencies, &num_freq, default_freq, 2);
+   config->get_float_array(userdata, "gains", &gain, &num_gain, default_gain, 2);
+
+   if (!config->get_string(userdata, "impulse_response_output", &filter_path, ""))
+   {
+      config->free(filter_path);
+      filter_path = NULL;
+   }
+
+   num_gain = num_freq = MIN(num_gain, num_freq);
+
+   if (!(gains = (struct eq_gain*)calloc(num_gain, sizeof(*gains))))
+      goto error;
+
+   for (i = 0; i < num_gain; i++)
+   {
+      gains[i].freq = frequencies[i] / (0.5f * info->input_rate);
+      gains[i].gain = pow(10.0, gain[i] / 20.0);
+   }
+   config->free(frequencies);
+   config->free(gain);
+
+   eq->block_size = size;
+
+   eq->save       = (float*)calloc(    size, 2 * sizeof(*eq->save));
+   eq->block      = (float*)calloc(2 * size, 2 * sizeof(*eq->block));
+   eq->fftblock   = (fft_complex_t*)calloc(2 * size, sizeof(*eq->fftblock));
+   eq->filter     = (fft_complex_t*)calloc(2 * size, sizeof(*eq->filter));
+
+   /* Use an FFT which is twice the block size with zero-padding
+    * to make circular convolution => proper convolution.
+    */
+   eq->fft        = fft_new(size_log2 + 1);
+
+   if (!eq->fft || !eq->fftblock || !eq->save || !eq->block || !eq->filter)
+      goto error;
+
+   create_filter(eq, size_log2, gains, num_gain, beta, filter_path);
+   config->free(filter_path);
+   filter_path = NULL;
+
+   free(gains);
+   return eq;
+
+error:
+   free(gains);
+   eq_free(eq);
+   return NULL;
+}
+
+static const struct dspfilter_implementation eq_plug = {
+   eq_init,
+   eq_process,
+   eq_free,
+
+   DSPFILTER_API_VERSION,
+   "Linear-Phase FFT Equalizer",
+   "eq",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation eq_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &eq_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/fft/fft.c b/deps/libretro-common/audio/dsp_filters/fft/fft.c
new file mode 100644 (file)
index 0000000..3d63d32
--- /dev/null
@@ -0,0 +1,204 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fft.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+
+#include "fft.h"
+
+#include <retro_miscellaneous.h>
+
+struct fft
+{
+   fft_complex_t *interleave_buffer;
+   fft_complex_t *phase_lut;
+   unsigned *bitinverse_buffer;
+   unsigned size;
+};
+
+static unsigned bitswap(unsigned x, unsigned size_log2)
+{
+   unsigned i;
+   unsigned ret = 0;
+   for (i = 0; i < size_log2; i++)
+      ret |= ((x >> i) & 1) << (size_log2 - i - 1);
+   return ret;
+}
+
+static void build_bitinverse(unsigned *bitinverse, unsigned size_log2)
+{
+   unsigned i;
+   unsigned size = 1 << size_log2;
+   for (i = 0; i < size; i++)
+      bitinverse[i] = bitswap(i, size_log2);
+}
+
+static fft_complex_t exp_imag(double phase)
+{
+   fft_complex_t out = { cos(phase), sin(phase) };
+   return out;
+}
+
+static void build_phase_lut(fft_complex_t *out, int size)
+{
+   int i;
+   out += size;
+   for (i = -size; i <= size; i++)
+      out[i] = exp_imag((M_PI * i) / size);
+}
+
+static void interleave_complex(const unsigned *bitinverse,
+      fft_complex_t *out, const fft_complex_t *in,
+      unsigned samples, unsigned step)
+{
+   unsigned i;
+   for (i = 0; i < samples; i++, in += step)
+      out[bitinverse[i]] = *in;
+}
+
+static void interleave_float(const unsigned *bitinverse,
+      fft_complex_t *out, const float *in,
+      unsigned samples, unsigned step)
+{
+   unsigned i;
+   for (i = 0; i < samples; i++, in += step)
+   {
+      unsigned inv_i = bitinverse[i];
+      out[inv_i].real = *in;
+      out[inv_i].imag = 0.0f;
+   }
+}
+
+static void resolve_float(float *out, const fft_complex_t *in, unsigned samples,
+      float gain, unsigned step)
+{
+   unsigned i;
+   for (i = 0; i < samples; i++, in++, out += step)
+      *out = gain * in->real;
+}
+
+fft_t *fft_new(unsigned block_size_log2)
+{
+   unsigned size;
+   fft_t *fft = (fft_t*)calloc(1, sizeof(*fft));
+   if (!fft)
+      return NULL;
+
+   size                   = 1 << block_size_log2;
+   fft->interleave_buffer = (fft_complex_t*)calloc(size, sizeof(*fft->interleave_buffer));
+   fft->bitinverse_buffer = (unsigned*)calloc(size, sizeof(*fft->bitinverse_buffer));
+   fft->phase_lut         = (fft_complex_t*)calloc(2 * size + 1, sizeof(*fft->phase_lut));
+
+   if (!fft->interleave_buffer || !fft->bitinverse_buffer || !fft->phase_lut)
+      goto error;
+
+   fft->size = size;
+
+   build_bitinverse(fft->bitinverse_buffer, block_size_log2);
+   build_phase_lut(fft->phase_lut, size);
+   return fft;
+
+error:
+   fft_free(fft);
+   return NULL;
+}
+
+void fft_free(fft_t *fft)
+{
+   if (!fft)
+      return;
+
+   free(fft->interleave_buffer);
+   free(fft->bitinverse_buffer);
+   free(fft->phase_lut);
+   free(fft);
+}
+
+static void butterfly(fft_complex_t *a, fft_complex_t *b, fft_complex_t mod)
+{
+   mod = fft_complex_mul(mod, *b);
+   *b  = fft_complex_sub(*a, mod);
+   *a  = fft_complex_add(*a, mod);
+}
+
+static void butterflies(fft_complex_t *butterfly_buf,
+      const fft_complex_t *phase_lut,
+      int phase_dir, unsigned step_size, unsigned samples)
+{
+   unsigned i, j;
+   for (i = 0; i < samples; i += step_size << 1)
+   {
+      int phase_step = (int)samples * phase_dir / (int)step_size;
+      for (j = i; j < i + step_size; j++)
+         butterfly(&butterfly_buf[j], &butterfly_buf[j + step_size],
+               phase_lut[phase_step * (int)(j - i)]);
+   }
+}
+
+void fft_process_forward_complex(fft_t *fft,
+      fft_complex_t *out, const fft_complex_t *in, unsigned step)
+{
+   unsigned step_size;
+   unsigned samples = fft->size;
+   interleave_complex(fft->bitinverse_buffer, out, in, samples, step);
+
+   for (step_size = 1; step_size < samples; step_size <<= 1)
+   {
+      butterflies(out,
+            fft->phase_lut + samples,
+            -1, step_size, samples);
+   }
+}
+
+void fft_process_forward(fft_t *fft,
+      fft_complex_t *out, const float *in, unsigned step)
+{
+   unsigned step_size;
+   unsigned samples = fft->size;
+   interleave_float(fft->bitinverse_buffer, out, in, samples, step);
+
+   for (step_size = 1; step_size < fft->size; step_size <<= 1)
+   {
+      butterflies(out,
+            fft->phase_lut + samples,
+            -1, step_size, samples);
+   }
+}
+
+void fft_process_inverse(fft_t *fft,
+      float *out, const fft_complex_t *in, unsigned step)
+{
+   unsigned step_size;
+   unsigned samples = fft->size;
+
+   interleave_complex(fft->bitinverse_buffer, fft->interleave_buffer,
+         in, samples, 1);
+
+   for (step_size = 1; step_size < samples; step_size <<= 1)
+   {
+      butterflies(fft->interleave_buffer,
+            fft->phase_lut + samples,
+            1, step_size, samples);
+   }
+
+   resolve_float(out, fft->interleave_buffer, samples, 1.0f / samples, step);
+}
diff --git a/deps/libretro-common/audio/dsp_filters/fft/fft.h b/deps/libretro-common/audio/dsp_filters/fft/fft.h
new file mode 100644 (file)
index 0000000..50c191d
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fft.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 RARCH_FFT_H__
+#define RARCH_FFT_H__
+
+#include <retro_inline.h>
+#include <math/complex.h>
+
+typedef struct fft fft_t;
+
+fft_t *fft_new(unsigned block_size_log2);
+
+void fft_free(fft_t *fft);
+
+void fft_process_forward_complex(fft_t *fft,
+      fft_complex_t *out, const fft_complex_t *in, unsigned step);
+
+void fft_process_forward(fft_t *fft,
+      fft_complex_t *out, const float *in, unsigned step);
+
+void fft_process_inverse(fft_t *fft,
+      float *out, const fft_complex_t *in, unsigned step);
+
+#endif
diff --git a/deps/libretro-common/audio/dsp_filters/iir.c b/deps/libretro-common/audio/dsp_filters/iir.c
new file mode 100644 (file)
index 0000000..232edc1
--- /dev/null
@@ -0,0 +1,370 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (iir.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+#include <string/stdstring.h>
+
+#define sqr(a) ((a) * (a))
+
+/* filter types */
+enum IIRFilter
+{
+   LPF,        /* low pass filter */
+   HPF,        /* High pass filter */
+   BPCSGF,     /* band pass filter 1 */
+   BPZPGF,     /* band pass filter 2 */
+   APF,        /* Allpass filter*/
+   NOTCH,      /* Notch Filter */
+   RIAA_phono, /* RIAA record/tape deemphasis */
+   PEQ,        /* Peaking band EQ filter */
+   BBOOST,     /* Bassboost filter */
+   LSH,        /* Low shelf filter */
+   HSH,        /* High shelf filter */
+   RIAA_CD     /* CD de-emphasis */
+};
+
+struct iir_data
+{
+   float b0, b1, b2;
+   float a0, a1, a2;
+
+   struct
+   {
+      float xn1, xn2;
+      float yn1, yn2;
+   } l, r;
+};
+
+static void iir_free(void *data)
+{
+   free(data);
+}
+
+static void iir_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i;
+   struct iir_data *iir = (struct iir_data*)data;
+   float *out           = output->samples;
+
+   float b0             = iir->b0;
+   float b1             = iir->b1;
+   float b2             = iir->b2;
+   float a0             = iir->a0;
+   float a1             = iir->a1;
+   float a2             = iir->a2;
+
+   float xn1_l          = iir->l.xn1;
+   float xn2_l          = iir->l.xn2;
+   float yn1_l          = iir->l.yn1;
+   float yn2_l          = iir->l.yn2;
+
+   float xn1_r          = iir->r.xn1;
+   float xn2_r          = iir->r.xn2;
+   float yn1_r          = iir->r.yn1;
+   float yn2_r          = iir->r.yn2;
+
+   output->samples      = input->samples;
+   output->frames       = input->frames;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float in_l = out[0];
+      float in_r = out[1];
+
+      float l    = (b0 * in_l + b1 * xn1_l + b2 * xn2_l - a1 * yn1_l - a2 * yn2_l) / a0;
+      float r    = (b0 * in_r + b1 * xn1_r + b2 * xn2_r - a1 * yn1_r - a2 * yn2_r) / a0;
+
+      xn2_l      = xn1_l;
+      xn1_l      = in_l;
+      yn2_l      = yn1_l;
+      yn1_l      = l;
+
+      xn2_r      = xn1_r;
+      xn1_r      = in_r;
+      yn2_r      = yn1_r;
+      yn1_r      = r;
+
+      out[0]     = l;
+      out[1]     = r;
+   }
+
+   iir->l.xn1 = xn1_l;
+   iir->l.xn2 = xn2_l;
+   iir->l.yn1 = yn1_l;
+   iir->l.yn2 = yn2_l;
+
+   iir->r.xn1 = xn1_r;
+   iir->r.xn2 = xn2_r;
+   iir->r.yn1 = yn1_r;
+   iir->r.yn2 = yn2_r;
+}
+
+#define CHECK(x) if (string_is_equal(str, #x)) return x
+static enum IIRFilter str_to_type(const char *str)
+{
+   CHECK(LPF);
+   CHECK(HPF);
+   CHECK(BPCSGF);
+   CHECK(BPZPGF);
+   CHECK(APF);
+   CHECK(NOTCH);
+   CHECK(RIAA_phono);
+   CHECK(PEQ);
+   CHECK(BBOOST);
+   CHECK(LSH);
+   CHECK(HSH);
+   CHECK(RIAA_CD);
+
+   return LPF; /* Fallback. */
+}
+
+static void make_poly_from_roots(
+      const double *roots, unsigned num_roots, float *poly)
+{
+   unsigned i, j;
+
+   poly[0] = 1;
+   poly[1] = -roots[0];
+   memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));
+
+   for (i = 1; i < num_roots; i++)
+      for (j = num_roots; j > 0; j--)
+         poly[j] -= poly[j - 1] * roots[i];
+}
+
+static void iir_filter_init(struct iir_data *iir,
+      float sample_rate, float freq, float qual, float gain, enum IIRFilter filter_type)
+{
+       double omega = 2.0 * M_PI * freq / sample_rate;
+   double cs    = cos(omega);
+   double sn    = sin(omega);
+   double a1pha = sn / (2.0 * qual);
+   double A     = exp(log(10.0) * gain / 40.0);
+   double beta  = sqrt(A + A);
+
+   float b0     = 0.0, b1 = 0.0, b2 = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0;
+
+   /* Set up filter coefficients according to type */
+   switch (filter_type)
+   {
+      case LPF:
+         b0 =  (1.0 - cs) / 2.0;
+         b1 =   1.0 - cs ;
+         b2 =  (1.0 - cs) / 2.0;
+         a0 =   1.0 + a1pha;
+         a1 =  -2.0 * cs;
+         a2 =   1.0 - a1pha;
+         break;
+      case HPF:
+         b0 =  (1.0 + cs) / 2.0;
+         b1 = -(1.0 + cs);
+         b2 =  (1.0 + cs) / 2.0;
+         a0 =   1.0 + a1pha;
+         a1 =  -2.0 * cs;
+         a2 =   1.0 - a1pha;
+         break;
+      case APF:
+         b0 =  1.0 - a1pha;
+         b1 = -2.0 * cs;
+         b2 =  1.0 + a1pha;
+         a0 =  1.0 + a1pha;
+         a1 = -2.0 * cs;
+         a2 =  1.0 - a1pha;
+         break;
+      case BPZPGF:
+         b0 =  a1pha;
+         b1 =  0.0;
+         b2 = -a1pha;
+         a0 =  1.0 + a1pha;
+         a1 = -2.0 * cs;
+         a2 =  1.0 - a1pha;
+         break;
+      case BPCSGF:
+         b0 =  sn / 2.0;
+         b1 =  0.0;
+         b2 = -sn / 2.0;
+         a0 =  1.0 + a1pha;
+         a1 = -2.0 * cs;
+         a2 =  1.0 - a1pha;
+         break;
+      case NOTCH:
+         b0 =  1.0;
+         b1 = -2.0 * cs;
+         b2 =  1.0;
+         a0 =  1.0 + a1pha;
+         a1 = -2.0 * cs;
+         a2 =  1.0 - a1pha;
+         break;
+      case RIAA_phono: /* http://www.dsprelated.com/showmessage/73300/3.php */
+      {
+         double y, b_re, a_re, b_im, a_im, g;
+         float b[3] = {0.0f};
+         float a[3] = {0.0f};
+
+         if ((int)sample_rate == 44100)
+         {
+            static const double zeros[] = {-0.2014898, 0.9233820};
+            static const double poles[] = {0.7083149, 0.9924091};
+            make_poly_from_roots(zeros, 2, b);
+            make_poly_from_roots(poles, 2, a);
+         }
+         else if ((int)sample_rate == 48000)
+         {
+            static const double zeros[] = {-0.1766069, 0.9321590};
+            static const double poles[] = {0.7396325, 0.9931330};
+            make_poly_from_roots(zeros, 2, b);
+            make_poly_from_roots(poles, 2, a);
+         }
+         else if ((int)sample_rate == 88200)
+         {
+            static const double zeros[] = {-0.1168735, 0.9648312};
+            static const double poles[] = {0.8590646, 0.9964002};
+            make_poly_from_roots(zeros, 2, b);
+            make_poly_from_roots(poles, 2, a);
+         }
+         else if ((int)sample_rate == 96000)
+         {
+            static const double zeros[] = {-0.1141486, 0.9676817};
+            static const double poles[] = {0.8699137, 0.9966946};
+            make_poly_from_roots(zeros, 2, b);
+            make_poly_from_roots(poles, 2, a);
+         }
+
+         b0    = b[0];
+         b1    = b[1];
+         b2    = b[2];
+         a0    = a[0];
+         a1    = a[1];
+         a2    = a[2];
+
+         /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */
+         y     = 2.0 * M_PI * 1000.0 / sample_rate;
+         b_re  = b0 + b1 * cos(-y) + b2 * cos(-2.0 * y);
+         a_re  = a0 + a1 * cos(-y) + a2 * cos(-2.0 * y);
+         b_im  = b1 * sin(-y) + b2 * sin(-2.0 * y);
+         a_im  = a1 * sin(-y) + a2 * sin(-2.0 * y);
+         g     = 1.0 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));
+         b0   *= g; b1 *= g; b2 *= g;
+         break;
+      }
+      case PEQ:
+         b0 =  1.0 + a1pha * A;
+         b1 = -2.0 * cs;
+         b2 =  1.0 - a1pha * A;
+         a0 =  1.0 + a1pha / A;
+         a1 = -2.0 * cs;
+         a2 =  1.0 - a1pha / A;
+         break;
+      case BBOOST:
+         beta = sqrt((A * A + 1) / 1.0 - (pow((A - 1), 2)));
+         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
+         b1 = 2 * A * ((A - 1) - (A + 1) * cs);
+         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
+         a0 = ((A + 1) + (A - 1) * cs + beta * sn);
+         a1 = -2 * ((A - 1) + (A + 1) * cs);
+         a2 = (A + 1) + (A - 1) * cs - beta * sn;
+         break;
+      case LSH:
+         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);
+         b1 = 2 * A * ((A - 1) - (A + 1) * cs);
+         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);
+         a0 = (A + 1) + (A - 1) * cs + beta * sn;
+         a1 = -2 * ((A - 1) + (A + 1) * cs);
+         a2 = (A + 1) + (A - 1) * cs - beta * sn;
+         break;
+      case RIAA_CD:
+         omega = 2.0 * M_PI * 5283.0 / sample_rate;
+         cs = cos(omega);
+         sn = sin(omega);
+         a1pha = sn / (2.0 * 0.4845);
+         A = exp(log(10.0) * -9.477 / 40.0);
+         beta = sqrt(A + A);
+         (void)a1pha;
+      case HSH:
+         b0 = A * ((A + 1.0) + (A - 1.0) * cs + beta * sn);
+         b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * cs);
+         b2 = A * ((A + 1.0) + (A - 1.0) * cs - beta * sn);
+         a0 = (A + 1.0) - (A - 1.0) * cs + beta * sn;
+         a1 = 2.0 * ((A - 1.0) - (A + 1.0) * cs);
+         a2 = (A + 1.0) - (A - 1.0) * cs - beta * sn;
+         break;
+      default:
+         break;
+   }
+
+   iir->b0 = b0;
+   iir->b1 = b1;
+   iir->b2 = b2;
+   iir->a0 = a0;
+   iir->a1 = a1;
+   iir->a2 = a2;
+}
+
+static void *iir_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   float freq, qual, gain;
+   enum IIRFilter filter  = LPF;
+   char           *type   = NULL;
+   struct iir_data *iir   = (struct iir_data*)calloc(1, sizeof(*iir));
+   if (!iir)
+      return NULL;
+
+   config->get_float(userdata, "frequency", &freq, 1024.0f);
+   config->get_float(userdata, "quality", &qual, 0.707f);
+   config->get_float(userdata, "gain", &gain, 0.0f);
+
+   config->get_string(userdata, "type", &type, "LPF");
+
+   filter = str_to_type(type);
+   config->free(type);
+
+   iir_filter_init(iir, info->input_rate, freq, qual, gain, filter);
+   return iir;
+}
+
+static const struct dspfilter_implementation iir_plug = {
+   iir_init,
+   iir_process,
+   iir_free,
+
+   DSPFILTER_API_VERSION,
+   "IIR",
+   "iir",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation iir_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &iir_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/link.T b/deps/libretro-common/audio/dsp_filters/link.T
new file mode 100644 (file)
index 0000000..bd9ad79
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  global: dspfilter_get_implementation;
+  local: *;
+};
diff --git a/deps/libretro-common/audio/dsp_filters/panning.c b/deps/libretro-common/audio/dsp_filters/panning.c
new file mode 100644 (file)
index 0000000..87216ed
--- /dev/null
@@ -0,0 +1,110 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (panning.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libretro_dspfilter.h>
+
+struct panning_data
+{
+   float left[2];
+   float right[2];
+};
+
+static void panning_free(void *data)
+{
+   free(data);
+}
+
+static void panning_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i;
+   struct panning_data *pan = (struct panning_data*)data;
+   float *out               = output->samples;
+
+   output->samples          = input->samples;
+   output->frames           = input->frames;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float left  = out[0];
+      float right = out[1];
+      out[0]      = left * pan->left[0]  + right * pan->left[1];
+      out[1]      = left * pan->right[0] + right * pan->right[1];
+   }
+}
+
+static void *panning_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   static const float default_left[]  = { 1.0f, 0.0f };
+   static const float default_right[] = { 0.0f, 1.0f };
+   float *left                        = NULL;
+   float *right                       = NULL;
+   unsigned num_left                  = 0;
+   unsigned num_right                 = 0;
+   struct panning_data *pan           = (struct panning_data*)
+      calloc(1, sizeof(*pan));
+
+   if (!pan)
+      return NULL;
+
+   config->get_float_array(userdata, "left_mix",
+         &left, &num_left, default_left, 2);
+   config->get_float_array(userdata, "right_mix",
+         &right, &num_right, default_right, 2);
+
+   memcpy(pan->left,  (num_left  == 2) ?
+         left :  default_left,  sizeof(pan->left));
+   memcpy(pan->right, (num_right == 2) ?
+         right : default_right, sizeof(pan->right));
+
+   config->free(left);
+   config->free(right);
+
+   return pan;
+}
+
+static const struct dspfilter_implementation panning = {
+   panning_init,
+   panning_process,
+   panning_free,
+
+   DSPFILTER_API_VERSION,
+   "Panning",
+   "panning",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation panning_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *
+dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &panning;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/phaser.c b/deps/libretro-common/audio/dsp_filters/phaser.c
new file mode 100644 (file)
index 0000000..4c5d206
--- /dev/null
@@ -0,0 +1,144 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (phaser.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+
+#define PHASER_LFO_SHAPE 4.0
+#define PHASER_LFO_SKIP_SAMPLES 20
+
+struct phaser_data
+{
+   float freq;
+   float startphase;
+   float fb;
+   float depth;
+   float drywet;
+   float old[2][24];
+   float gain;
+   float fbout[2];
+   float lfoskip;
+   float phase;
+
+   int stages;
+   unsigned long skipcount;
+};
+
+static void phaser_free(void *data)
+{
+   free(data);
+}
+
+static void phaser_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i, c;
+   int s;
+   float m[2], tmp[2];
+   struct phaser_data *ph = (struct phaser_data*)data;
+   float *out             = output->samples;
+
+   output->samples        = input->samples;
+   output->frames         = input->frames;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float in[2] = { out[0], out[1] };
+
+      for (c = 0; c < 2; c++)
+         m[c] = in[c] + ph->fbout[c] * ph->fb * 0.01f;
+
+      if ((ph->skipcount++ % PHASER_LFO_SKIP_SAMPLES) == 0)
+      {
+         ph->gain = 0.5 * (1.0 + cos(ph->skipcount * ph->lfoskip + ph->phase));
+         ph->gain = (exp(ph->gain * PHASER_LFO_SHAPE) - 1.0) / (exp(PHASER_LFO_SHAPE) - 1);
+         ph->gain = 1.0 - ph->gain * ph->depth;
+      }
+
+      for (s = 0; s < ph->stages; s++)
+      {
+         for (c = 0; c < 2; c++)
+         {
+            tmp[c] = ph->old[c][s];
+            ph->old[c][s] = ph->gain * tmp[c] + m[c];
+            m[c] = tmp[c] - ph->gain * ph->old[c][s];
+         }
+      }
+
+      for (c = 0; c < 2; c++)
+      {
+         ph->fbout[c] = m[c];
+         out[c] = m[c] * ph->drywet + in[c] * (1.0f - ph->drywet);
+      }
+   }
+}
+
+static void *phaser_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   float lfo_freq, lfo_start_phase;
+   struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));
+   if (!ph)
+      return NULL;
+
+   config->get_float(userdata, "lfo_freq", &lfo_freq, 0.4f);
+   config->get_float(userdata, "lfo_start_phase", &lfo_start_phase, 0.0f);
+   config->get_float(userdata, "feedback", &ph->fb, 0.0f);
+   config->get_float(userdata, "depth", &ph->depth, 0.4f);
+   config->get_float(userdata, "dry_wet", &ph->drywet, 0.5f);
+   config->get_int(userdata, "stages", &ph->stages, 2);
+
+   if (ph->stages < 1)
+      ph->stages = 1;
+   else if (ph->stages > 24)
+      ph->stages = 24;
+
+   ph->lfoskip = lfo_freq * 2.0 * M_PI / info->input_rate;
+   ph->phase   = lfo_start_phase * M_PI / 180.0;
+
+   return ph;
+}
+
+static const struct dspfilter_implementation phaser_plug = {
+   phaser_init,
+   phaser_process,
+   phaser_free,
+
+   DSPFILTER_API_VERSION,
+   "Phaser",
+   "phaser",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation phaser_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &phaser_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/reverb.c b/deps/libretro-common/audio/dsp_filters/reverb.c
new file mode 100644 (file)
index 0000000..10559b3
--- /dev/null
@@ -0,0 +1,315 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (reverb.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_inline.h>
+#include <libretro_dspfilter.h>
+
+struct comb
+{
+   float *buffer;
+   unsigned bufsize;
+   unsigned bufidx;
+
+   float feedback;
+   float filterstore;
+   float damp1, damp2;
+};
+
+struct allpass
+{
+   float *buffer;
+   float feedback;
+   unsigned bufsize;
+   unsigned bufidx;
+};
+
+static INLINE float comb_process(struct comb *c, float input)
+{
+   float output         = c->buffer[c->bufidx];
+   c->filterstore       = (output * c->damp2) + (c->filterstore * c->damp1);
+
+   c->buffer[c->bufidx] = input + (c->filterstore * c->feedback);
+
+   c->bufidx++;
+   if (c->bufidx >= c->bufsize)
+      c->bufidx = 0;
+
+   return output;
+}
+
+static INLINE float allpass_process(struct allpass *a, float input)
+{
+   float bufout         = a->buffer[a->bufidx];
+   float output         = -input + bufout;
+   a->buffer[a->bufidx] = input + bufout * a->feedback;
+
+   a->bufidx++;
+   if (a->bufidx >= a->bufsize)
+      a->bufidx = 0;
+
+   return output;
+}
+
+#define numcombs 8
+#define numallpasses 4
+static const float muted = 0;
+static const float fixedgain = 0.015f;
+static const float scalewet = 3;
+static const float scaledry = 2;
+static const float scaledamp = 0.4f;
+static const float scaleroom = 0.28f;
+static const float offsetroom = 0.7f;
+static const float initialroom = 0.5f;
+static const float initialdamp = 0.5f;
+static const float initialwet = 1.0f / 3.0f;
+static const float initialdry = 0;
+static const float initialwidth = 1;
+static const float initialmode = 0;
+static const float freezemode = 0.5f;
+
+struct revmodel
+{
+   struct comb combL[numcombs];
+   struct allpass allpassL[numallpasses];
+
+   float *bufcomb[numcombs];
+   float *bufallpass[numallpasses];
+
+   float gain;
+   float roomsize, roomsize1;
+   float damp, damp1;
+   float wet, wet1, wet2;
+   float dry;
+   float width;
+   float mode;
+};
+
+static float revmodel_process(struct revmodel *rev, float in)
+{
+   int i;
+   float mono_out = 0.0f;
+   float mono_in  = in;
+   float input    = mono_in * rev->gain;
+
+   for (i = 0; i < numcombs; i++)
+      mono_out += comb_process(&rev->combL[i], input);
+
+   for (i = 0; i < numallpasses; i++)
+      mono_out = allpass_process(&rev->allpassL[i], mono_out);
+
+   return mono_in * rev->dry + mono_out * rev->wet1;
+}
+
+static void revmodel_update(struct revmodel *rev)
+{
+   int i;
+   rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
+
+   if (rev->mode >= freezemode)
+   {
+      rev->roomsize1 = 1.0f;
+      rev->damp1 = 0.0f;
+      rev->gain = muted;
+   }
+   else
+   {
+      rev->roomsize1 = rev->roomsize;
+      rev->damp1 = rev->damp;
+      rev->gain = fixedgain;
+   }
+
+   for (i = 0; i < numcombs; i++)
+   {
+      rev->combL[i].feedback = rev->roomsize1;
+      rev->combL[i].damp1 = rev->damp1;
+      rev->combL[i].damp2 = 1.0f - rev->damp1;
+   }
+}
+
+static void revmodel_setroomsize(struct revmodel *rev, float value)
+{
+   rev->roomsize = value * scaleroom + offsetroom;
+   revmodel_update(rev);
+}
+
+static void revmodel_setdamp(struct revmodel *rev, float value)
+{
+   rev->damp = value * scaledamp;
+   revmodel_update(rev);
+}
+
+static void revmodel_setwet(struct revmodel *rev, float value)
+{
+   rev->wet = value * scalewet;
+   revmodel_update(rev);
+}
+
+static void revmodel_setdry(struct revmodel *rev, float value)
+{
+   rev->dry = value * scaledry;
+   revmodel_update(rev);
+}
+
+static void revmodel_setwidth(struct revmodel *rev, float value)
+{
+   rev->width = value;
+   revmodel_update(rev);
+}
+
+static void revmodel_setmode(struct revmodel *rev, float value)
+{
+   rev->mode = value;
+   revmodel_update(rev);
+}
+
+static void revmodel_init(struct revmodel *rev,int srate)
+{
+
+  static const int comb_lengths[8] = { 1116,1188,1277,1356,1422,1491,1557,1617 };
+  static const int allpass_lengths[4] = { 225,341,441,556 };
+  double r = srate * (1 / 44100.0);
+  unsigned c;
+
+   for (c = 0; c < numcombs; ++c)
+   {
+          rev->bufcomb[c] = malloc(r*comb_lengths[c]*sizeof(float));
+          rev->combL[c].buffer  =  rev->bufcomb[c];
+         memset(rev->combL[c].buffer,0,r*comb_lengths[c]*sizeof(float));
+         rev->combL[c].bufsize=r*comb_lengths[c];
+  }
+
+   for (c = 0; c < numallpasses; ++c)
+   {
+          rev->bufallpass[c] = malloc(r*allpass_lengths[c]*sizeof(float));
+          rev->allpassL[c].buffer  =  rev->bufallpass[c];
+         memset(rev->allpassL[c].buffer,0,r*allpass_lengths[c]*sizeof(float));
+         rev->allpassL[c].bufsize=r*allpass_lengths[c];
+         rev->allpassL[c].feedback = 0.5f;
+  }
+
+   revmodel_setwet(rev, initialwet);
+   revmodel_setroomsize(rev, initialroom);
+   revmodel_setdry(rev, initialdry);
+   revmodel_setdamp(rev, initialdamp);
+   revmodel_setwidth(rev, initialwidth);
+   revmodel_setmode(rev, initialmode);
+}
+
+struct reverb_data
+{
+   struct revmodel left, right;
+};
+
+static void reverb_free(void *data)
+{
+   struct reverb_data *rev = (struct reverb_data*)data;
+   unsigned i;
+
+   for (i = 0; i < numcombs; i++) {
+   free(rev->left.bufcomb[i]);
+   free(rev->right.bufcomb[i]);
+   }
+
+   for (i = 0; i < numallpasses; i++) {
+   free(rev->left.bufallpass[i]);
+   free(rev->right.bufallpass[i]);
+   }
+   free(data);
+}
+
+static void reverb_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i;
+   float *out;
+   struct reverb_data *rev = (struct reverb_data*)data;
+
+   output->samples         = input->samples;
+   output->frames          = input->frames;
+   out                     = output->samples;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float in[2] = { out[0], out[1] };
+
+      out[0] = revmodel_process(&rev->left, in[0]);
+      out[1] = revmodel_process(&rev->right, in[1]);
+   }
+}
+
+static void *reverb_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   float drytime, wettime, damping, roomwidth, roomsize;
+   struct reverb_data *rev = (struct reverb_data*)
+      calloc(1, sizeof(*rev));
+   if (!rev)
+      return NULL;
+
+   config->get_float(userdata, "drytime", &drytime, 0.43f);
+   config->get_float(userdata, "wettime", &wettime, 0.4f);
+   config->get_float(userdata, "damping", &damping, 0.8f);
+   config->get_float(userdata, "roomwidth", &roomwidth, 0.56f);
+   config->get_float(userdata, "roomsize", &roomsize, 0.56f);
+
+   revmodel_init(&rev->left,info->input_rate);
+   revmodel_init(&rev->right,info->input_rate);
+
+   revmodel_setdamp(&rev->left, damping);
+   revmodel_setdry(&rev->left, drytime);
+   revmodel_setwet(&rev->left, wettime);
+   revmodel_setwidth(&rev->left, roomwidth);
+   revmodel_setroomsize(&rev->left, roomsize);
+
+   revmodel_setdamp(&rev->right, damping);
+   revmodel_setdry(&rev->right, drytime);
+   revmodel_setwet(&rev->right, wettime);
+   revmodel_setwidth(&rev->right, roomwidth);
+   revmodel_setroomsize(&rev->right, roomsize);
+
+   return rev;
+}
+
+static const struct dspfilter_implementation reverb_plug = {
+   reverb_init,
+   reverb_process,
+   reverb_free,
+
+   DSPFILTER_API_VERSION,
+   "Reverb",
+   "reverb",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation reverb_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &reverb_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/tremolo.c b/deps/libretro-common/audio/dsp_filters/tremolo.c
new file mode 100644 (file)
index 0000000..5bdf52e
--- /dev/null
@@ -0,0 +1,131 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (tremolo.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+#include <string/stdstring.h>
+
+#define sqr(a) ((a) * (a))
+
+struct tremolo_core
+{
+   float *wavetable;
+   float freq;
+   float depth;
+   int index;
+   int maxindex;
+};
+
+struct tremolo
+{
+   struct tremolo_core left, right;
+};
+
+static void tremolo_free(void *data)
+{
+   struct tremolo *tre = (struct tremolo*)data;
+   free(tre->left.wavetable);
+   free(tre->right.wavetable);
+   free(data);
+}
+
+static void tremolocore_init(struct tremolo_core *core,float depth,int samplerate,float freq)
+{
+   double env;
+   unsigned i;
+   const double offset = 1. - depth / 2.;
+   core->index     = 0;
+   core->maxindex  = samplerate / freq;
+   core->wavetable = malloc(core->maxindex   * sizeof(float));
+   memset(core->wavetable, 0, core->maxindex * sizeof(float));
+   for (i = 0; i < core->maxindex; i++)
+   {
+      env                = freq * i / samplerate;
+      env                = sin((M_PI*2) * fmod(env + 0.25, 1.0));
+      core->wavetable[i] = env * (1 - fabs(offset)) + offset;
+   }
+}
+
+float tremolocore_core(struct tremolo_core *core,float in)
+{
+   core->index = core->index % core->maxindex;
+   return in * core->wavetable[core->index++];
+}
+
+static void tremolo_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i;
+   float *out;
+   struct tremolo *tre = (struct tremolo*)data;
+
+   output->samples     = input->samples;
+   output->frames      = input->frames;
+   out                 = output->samples;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float in[2]      = { out[0], out[1] };
+      out[0]           = tremolocore_core(&tre->left, in[0]);
+      out[1]           = tremolocore_core(&tre->right, in[1]);
+   }
+}
+
+static void *tremolo_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   float freq, depth;
+   struct tremolo *tre = (struct tremolo*)calloc(1, sizeof(*tre));
+   if (!tre)
+      return NULL;
+
+   config->get_float(userdata, "freq", &freq,4.0f);
+   config->get_float(userdata, "depth", &depth, 0.9f);
+   tremolocore_init(&tre->left,depth,info->input_rate,freq);
+   tremolocore_init(&tre->right,depth,info->input_rate,freq);
+   return tre;
+}
+
+static const struct dspfilter_implementation tremolo_plug = {
+   tremolo_init,
+   tremolo_process,
+   tremolo_free,
+
+   DSPFILTER_API_VERSION,
+   "Tremolo",
+   "tremolo",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation tremolo_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &tremolo_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/vibrato.c b/deps/libretro-common/audio/dsp_filters/vibrato.c
new file mode 100644 (file)
index 0000000..2db906b
--- /dev/null
@@ -0,0 +1,167 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (vibrato.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+#include <string/stdstring.h>
+
+#define sqr(a) ((a) * (a))
+
+#define VIBRATO_BASE_DELAY_SEC 0.002f /* 2 ms */
+#define VIBRATO_FREQUENCY_DEFAULT_HZ 2.0f
+#define VIBRATO_FREQUENCY_MAX_HZ 14.0f
+#define VIBRATO_DEPTH_DEFAULT_PERCENT 50.0f
+#define VIBRATO_ADD_DELAY 3
+
+static float hermite_interp(float x, float *y)
+{
+   float c0 = y[1];
+   float c1 = (1.0f / 2.0f) * (y[2] - y[0]);
+   float c2 = (y[0] - (5.0f / 2.0f) * y[1]) + (2.0f * y[2] - (1.0f / 2.0f) * y[3]);
+   float c3 = (1.0f / 2.0f) * (y[3] - y[0]) + (3.0f / 2.0f) * (y[1] - y[2]);
+   return ((c3 * x + c2) * x + c1) * x + c0;
+}
+
+struct vibrato_core
+{
+   float* buffer;
+   float freq;
+   float samplerate;
+   float depth;
+   int phase;
+   int writeindex;
+   int size;
+};
+
+struct vibrato
+{
+   struct vibrato_core left, right;
+};
+
+static void vibrato_free(void *data)
+{
+   struct vibrato *vib = (struct vibrato*)data;
+   free(vib->left.buffer);
+   free(vib->right.buffer);
+   free(data);
+}
+
+static void vibratocore_init(struct vibrato_core *core,float depth,int samplerate,float freq)
+{
+       core->size       = VIBRATO_BASE_DELAY_SEC * samplerate * 2;
+       core->buffer     = malloc((core->size + VIBRATO_ADD_DELAY) * sizeof(float));
+       memset(core->buffer, 0, (core->size   + VIBRATO_ADD_DELAY) * sizeof(float));
+       core->samplerate = samplerate;
+       core->freq       = freq;
+       core->depth      = depth;
+       core->phase      = 0;
+       core->writeindex = 0;
+}
+
+float vibratocore_core(struct vibrato_core *core,float in)
+{
+   int ipart;
+   float delay, readindex, fpart, value;
+   float M                        = core->freq / core->samplerate;
+   int maxphase                   = core->samplerate / core->freq;
+   float lfo                      = sin(M * 2. * M_PI * core->phase++);
+   int maxdelay                   = VIBRATO_BASE_DELAY_SEC * core->samplerate;
+   core->phase                    = core->phase % maxphase;
+   lfo                            = (lfo + 1) * 1.; // transform from [-1; 1] to [0; 1]
+   delay                          =  lfo * core->depth * maxdelay;
+   delay                         += VIBRATO_ADD_DELAY;
+   readindex                      = core->writeindex - 1 - delay;
+   while (readindex < 0)
+      readindex                  += core->size;
+   while (readindex >= core->size)
+      readindex                  -= core->size;
+   ipart                          = (int)readindex;    /* Integer part of the delay */
+   fpart                          = readindex - ipart; /* fractional part of the delay */
+   value                          = hermite_interp(fpart, &(core->buffer[ipart]));
+   core->buffer[core->writeindex] = in;
+   if (core->writeindex < VIBRATO_ADD_DELAY)
+      core->buffer[core->size + core->writeindex] = in;
+   core->writeindex++;
+   if (core->writeindex == core->size)
+      core->writeindex = 0;
+   return value;
+}
+
+static void vibrato_process(void *data,
+      struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i;
+   float *out;
+   struct vibrato *vib = (struct vibrato*)data;
+
+   output->samples     = input->samples;
+   output->frames      = input->frames;
+   out                 = output->samples;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float in[2] = { out[0], out[1] };
+      out[0]      = vibratocore_core(&vib->left, in[0]);
+      out[1]      = vibratocore_core(&vib->right, in[1]);
+   }
+}
+
+static void *vibrato_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   float freq, depth;
+   struct vibrato *vib = (struct vibrato*)calloc(1, sizeof(*vib));
+   if (!vib)
+      return NULL;
+
+   config->get_float(userdata, "freq", &freq,5.0f);
+   config->get_float(userdata, "depth", &depth, 0.5f);
+   vibratocore_init(&vib->left,depth,info->input_rate,freq);
+   vibratocore_init(&vib->right,depth,info->input_rate,freq);
+   return vib;
+}
+
+static const struct dspfilter_implementation vibrato_plug = {
+   vibrato_init,
+   vibrato_process,
+   vibrato_free,
+
+   DSPFILTER_API_VERSION,
+   "Vibrato",
+   "vibrato",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation vibrato_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   return &vibrato_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/dsp_filters/wahwah.c b/deps/libretro-common/audio/dsp_filters/wahwah.c
new file mode 100644 (file)
index 0000000..fff8be7
--- /dev/null
@@ -0,0 +1,147 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (wahwah.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_miscellaneous.h>
+#include <libretro_dspfilter.h>
+
+#define WAHWAH_LFO_SKIP_SAMPLES 30
+
+struct wahwah_data
+{
+   float phase;
+   float lfoskip;
+   float b0, b1, b2, a0, a1, a2;
+   float freq, startphase;
+   float depth, freqofs, res;
+   unsigned long skipcount;
+
+   struct
+   {
+      float xn1, xn2, yn1, yn2;
+   } l, r;
+};
+
+static void wahwah_free(void *data)
+{
+   if (data)
+      free(data);
+}
+
+static void wahwah_process(void *data, struct dspfilter_output *output,
+      const struct dspfilter_input *input)
+{
+   unsigned i;
+   struct wahwah_data *wah = (struct wahwah_data*)data;
+   float *out              = output->samples;
+
+   output->samples         = input->samples;
+   output->frames          = input->frames;
+
+   for (i = 0; i < input->frames; i++, out += 2)
+   {
+      float out_l, out_r;
+      float in[2] = { out[0], out[1] };
+
+      if ((wah->skipcount++ % WAHWAH_LFO_SKIP_SAMPLES) == 0)
+      {
+         float omega, sn, cs, alpha;
+         float frequency = (1.0f + cos(wah->skipcount * wah->lfoskip + wah->phase)) / 2.0f;
+
+         frequency       = frequency * wah->depth * (1.0f - wah->freqofs) + wah->freqofs;
+         frequency       = exp((frequency - 1.0f) * 6.0f);
+
+         omega           = M_PI * frequency;
+         sn              = sin(omega);
+         cs              = cos(omega);
+         alpha           = sn / (2.0f * wah->res);
+
+         wah->b0         = (1.0f - cs) / 2.0f;
+         wah->b1         = 1.0f  - cs;
+         wah->b2         = (1.0f - cs) / 2.0f;
+         wah->a0         = 1.0f + alpha;
+         wah->a1         = -2.0f * cs;
+         wah->a2         = 1.0f - alpha;
+      }
+
+      out_l              = (wah->b0 * in[0] + wah->b1 * wah->l.xn1 + wah->b2 * wah->l.xn2 - wah->a1 * wah->l.yn1 - wah->a2 * wah->l.yn2) / wah->a0;
+      out_r              = (wah->b0 * in[1] + wah->b1 * wah->r.xn1 + wah->b2 * wah->r.xn2 - wah->a1 * wah->r.yn1 - wah->a2 * wah->r.yn2) / wah->a0;
+
+      wah->l.xn2         = wah->l.xn1;
+      wah->l.xn1         = in[0];
+      wah->l.yn2         = wah->l.yn1;
+      wah->l.yn1         = out_l;
+
+      wah->r.xn2         = wah->r.xn1;
+      wah->r.xn1         = in[1];
+      wah->r.yn2         = wah->r.yn1;
+      wah->r.yn1         = out_r;
+
+      out[0]             = out_l;
+      out[1]             = out_r;
+   }
+}
+
+static void *wahwah_init(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata)
+{
+   struct wahwah_data *wah = (struct wahwah_data*)calloc(1, sizeof(*wah));
+   if (!wah)
+      return NULL;
+
+   config->get_float(userdata, "lfo_freq", &wah->freq, 1.5f);
+   config->get_float(userdata, "lfo_start_phase", &wah->startphase, 0.0f);
+   config->get_float(userdata, "freq_offset", &wah->freqofs, 0.3f);
+   config->get_float(userdata, "depth", &wah->depth, 0.7f);
+   config->get_float(userdata, "resonance", &wah->res, 2.5f);
+
+   wah->lfoskip = wah->freq * 2.0f * M_PI / info->input_rate;
+   wah->phase   = wah->startphase * M_PI / 180.0f;
+
+   return wah;
+}
+
+static const struct dspfilter_implementation wahwah_plug = {
+   wahwah_init,
+   wahwah_process,
+   wahwah_free,
+
+   DSPFILTER_API_VERSION,
+   "Wah-Wah",
+   "wahwah",
+};
+
+#ifdef HAVE_FILTERS_BUILTIN
+#define dspfilter_get_implementation wahwah_dspfilter_get_implementation
+#endif
+
+const struct dspfilter_implementation *
+dspfilter_get_implementation(dspfilter_simd_mask_t mask)
+{
+   (void)mask;
+   return &wahwah_plug;
+}
+
+#undef dspfilter_get_implementation
diff --git a/deps/libretro-common/audio/resampler/audio_resampler.c b/deps/libretro-common/audio/resampler/audio_resampler.c
new file mode 100644 (file)
index 0000000..884d961
--- /dev/null
@@ -0,0 +1,189 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (audio_resampler.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <string.h>
+
+#include <string/stdstring.h>
+#include <features/features_cpu.h>
+#include <file/config_file_userdata.h>
+
+#include <audio/audio_resampler.h>
+
+static void resampler_null_process(void *a, struct resampler_data *b) { }
+static void resampler_null_free(void *a) { }
+static void *resampler_null_init(const struct resampler_config *a, double b,
+      enum resampler_quality c, resampler_simd_mask_t d) { return (void*)0; }
+
+retro_resampler_t null_resampler = {
+   resampler_null_init,
+   resampler_null_process,
+   resampler_null_free,
+   RESAMPLER_API_VERSION,
+   "null",
+   "null"
+};
+
+static const retro_resampler_t *resampler_drivers[] = {
+   &sinc_resampler,
+#ifdef HAVE_CC_RESAMPLER
+   &CC_resampler,
+#endif
+#ifdef HAVE_NEAREST_RESAMPLER
+   &nearest_resampler,
+#endif
+   &null_resampler,
+   NULL,
+};
+
+static const struct resampler_config resampler_config = {
+   config_userdata_get_float,
+   config_userdata_get_int,
+   config_userdata_get_float_array,
+   config_userdata_get_int_array,
+   config_userdata_get_string,
+   config_userdata_free,
+};
+
+/**
+ * find_resampler_driver_index:
+ * @ident                      : Identifier of resampler driver to find.
+ *
+ * Finds resampler driver index by @ident name.
+ *
+ * Returns: resampler driver index if resampler driver was found, otherwise
+ * -1.
+ **/
+static int find_resampler_driver_index(const char *ident)
+{
+   unsigned i;
+
+   for (i = 0; resampler_drivers[i]; i++)
+      if (string_is_equal_noncase(ident, resampler_drivers[i]->ident))
+         return i;
+   return -1;
+}
+
+/**
+ * find_resampler_driver:
+ * @ident                      : Identifier of resampler driver to find.
+ *
+ * Finds resampler by @ident name.
+ *
+ * Returns: resampler driver if resampler driver was found, otherwise
+ * NULL.
+ **/
+static const retro_resampler_t *find_resampler_driver(const char *ident)
+{
+   int i = find_resampler_driver_index(ident);
+
+   if (i >= 0)
+      return resampler_drivers[i];
+
+   return resampler_drivers[0];
+}
+
+/**
+ * resampler_append_plugs:
+ * @re                         : Resampler handle
+ * @backend                    : Resampler backend that is about to be set.
+ * @bw_ratio                   : Bandwidth ratio.
+ *
+ * Initializes resampler driver based on queried CPU features.
+ *
+ * Returns: true (1) if successfully initialized, otherwise false (0).
+ **/
+static bool resampler_append_plugs(void **re,
+      const retro_resampler_t **backend,
+      enum resampler_quality quality,
+      double bw_ratio)
+{
+   resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get();
+
+   if (*backend)
+      *re = (*backend)->init(&resampler_config, bw_ratio, quality, mask);
+
+   if (!*re)
+      return false;
+   return true;
+}
+
+
+/**
+ * audio_resampler_driver_find_handle:
+ * @idx                : index of driver to get handle to.
+ *
+ * Returns: handle to audio resampler driver at index. Can be NULL
+ * if nothing found.
+ **/
+const void *audio_resampler_driver_find_handle(int idx)
+{
+   const void *drv = resampler_drivers[idx];
+   if (!drv)
+      return NULL;
+   return drv;
+}
+
+/**
+ * audio_resampler_driver_find_ident:
+ * @idx                : index of driver to get handle to.
+ *
+ * Returns: Human-readable identifier of audio resampler driver at index.
+ * Can be NULL if nothing found.
+ **/
+const char *audio_resampler_driver_find_ident(int idx)
+{
+   const retro_resampler_t *drv = resampler_drivers[idx];
+   if (!drv)
+      return NULL;
+   return drv->ident;
+}
+
+/**
+ * retro_resampler_realloc:
+ * @re                         : Resampler handle
+ * @backend                    : Resampler backend that is about to be set.
+ * @ident                      : Identifier name for resampler we want.
+ * @bw_ratio                   : Bandwidth ratio.
+ *
+ * Reallocates resampler. Will free previous handle before
+ * allocating a new one. If ident is NULL, first resampler will be used.
+ *
+ * Returns: true (1) if successful, otherwise false (0).
+ **/
+bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
+      const char *ident, enum resampler_quality quality, double bw_ratio)
+{
+   if (*re && *backend)
+      (*backend)->free(*re);
+
+   *re      = NULL;
+   *backend = find_resampler_driver(ident);
+
+   if (!resampler_append_plugs(re, backend, quality, bw_ratio))
+   {
+      if (!*re)
+         *backend = NULL;
+      return false;
+   }
+
+   return true;
+}
diff --git a/deps/libretro-common/audio/resampler/drivers/nearest_resampler.c b/deps/libretro-common/audio/resampler/drivers/nearest_resampler.c
new file mode 100644 (file)
index 0000000..578f589
--- /dev/null
@@ -0,0 +1,84 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nearest_resampler.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <audio/audio_resampler.h>
+
+typedef struct rarch_nearest_resampler
+{
+   float fraction;
+} rarch_nearest_resampler_t;
+
+static void resampler_nearest_process(
+      void *re_, struct resampler_data *data)
+{
+   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
+   audio_frame_float_t  *inp     = (audio_frame_float_t*)data->data_in;
+   audio_frame_float_t  *inp_max = (audio_frame_float_t*)inp + data->input_frames;
+   audio_frame_float_t  *outp    = (audio_frame_float_t*)data->data_out;
+   float                   ratio = 1.0 / data->ratio;
+
+   while (inp != inp_max)
+   {
+      while (re->fraction > 1)
+      {
+         *outp++       = *inp;
+         re->fraction -= ratio;
+      }
+      re->fraction++;
+      inp++;
+   }
+
+   data->output_frames = (outp - (audio_frame_float_t*)data->data_out);
+}
+
+static void resampler_nearest_free(void *re_)
+{
+   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;
+   if (re)
+      free(re);
+}
+
+static void *resampler_nearest_init(const struct resampler_config *config,
+      double bandwidth_mod,
+      enum resampler_quality quality,
+      resampler_simd_mask_t mask)
+{
+   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)
+      calloc(1, sizeof(rarch_nearest_resampler_t));
+   if (!re)
+      return NULL;
+   re->fraction = 0;
+   return re;
+}
+
+retro_resampler_t nearest_resampler = {
+   resampler_nearest_init,
+   resampler_nearest_process,
+   resampler_nearest_free,
+   RESAMPLER_API_VERSION,
+   "nearest",
+   "nearest"
+};
diff --git a/deps/libretro-common/audio/resampler/drivers/sinc_resampler.c b/deps/libretro-common/audio/resampler/drivers/sinc_resampler.c
new file mode 100644 (file)
index 0000000..fa3a78a
--- /dev/null
@@ -0,0 +1,1025 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (sinc_resampler.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* Bog-standard windowed SINC implementation. */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include <retro_environment.h>
+#include <retro_inline.h>
+#include <filters.h>
+#include <memalign.h>
+
+#include <audio/audio_resampler.h>
+#include <filters.h>
+
+#ifdef __SSE__
+#include <xmmintrin.h>
+#endif
+
+#if defined(__AVX__)
+#include <immintrin.h>
+#endif
+
+/* Rough SNR values for upsampling:
+ * LOWEST: 40 dB
+ * LOWER: 55 dB
+ * NORMAL: 70 dB
+ * HIGHER: 110 dB
+ * HIGHEST: 140 dB
+ */
+
+/* TODO, make all this more configurable. */
+
+enum sinc_window
+{
+   SINC_WINDOW_NONE   = 0,
+   SINC_WINDOW_KAISER,
+   SINC_WINDOW_LANCZOS
+};
+
+/* For the little amount of taps we're using,
+ * SSE1 is faster than AVX for some reason.
+ * AVX code is kept here though as by increasing number
+ * of sinc taps, the AVX code is clearly faster than SSE1.
+ */
+
+typedef struct rarch_sinc_resampler
+{
+   /* A buffer for phase_table, buffer_l and buffer_r
+    * are created in a single calloc().
+    * Ensure that we get as good cache locality as we can hope for. */
+   float *main_buffer;
+   float *phase_table;
+   float *buffer_l;
+   float *buffer_r;
+   unsigned phase_bits;
+   unsigned subphase_bits;
+   unsigned subphase_mask;
+   unsigned taps;
+   unsigned ptr;
+   uint32_t time;
+   float subphase_mod;
+   float kaiser_beta;
+} rarch_sinc_resampler_t;
+
+#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
+
+#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
+void process_sinc_neon_asm(float *out, const float *left,
+      const float *right, const float *coeff, unsigned taps);
+#else
+#include <arm_neon.h>
+
+/* Assumes that taps >= 8, and that taps is a multiple of 8.
+ * Not bothering to reimplement this one for the external .S
+ */
+static void resampler_sinc_process_neon_kaiser(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+   while (frames)
+   {
+      while (frames && resamp->time >= phases)
+      {
+         /* Push in reverse to make filter more obvious. */
+         if (!resamp->ptr)
+            resamp->ptr = taps;
+         resamp->ptr--;
+
+         resamp->buffer_l[resamp->ptr + taps] =
+            resamp->buffer_l[resamp->ptr]     = *input++;
+
+         resamp->buffer_r[resamp->ptr + taps] =
+            resamp->buffer_r[resamp->ptr]     = *input++;
+
+         resamp->time                        -= phases;
+         frames--;
+      }
+
+      {
+         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+         while (resamp->time < phases)
+         {
+            unsigned phase           = resamp->time >> resamp->subphase_bits;
+            const float *phase_table = resamp->phase_table + phase * taps * 2;
+            const float *delta_table = phase_table + taps;
+            float32x4_t delta        = vdupq_n_f32((resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
+            int i;
+            float32x4_t p1 = {0, 0, 0, 0}, p2 = {0, 0, 0, 0};
+            float32x2_t p3, p4;
+
+            for (i = 0; i < (int)taps; i += 8)
+            {
+               float32x4x2_t coeff8  = vld2q_f32(&phase_table[i]);
+               float32x4x2_t delta8  = vld2q_f32(&delta_table[i]);
+               float32x4x2_t left8   = vld2q_f32(&buffer_l[i]);
+               float32x4x2_t right8  = vld2q_f32(&buffer_r[i]);
+
+               coeff8.val[0] = vmlaq_f32(coeff8.val[0], delta8.val[0], delta);
+               coeff8.val[1] = vmlaq_f32(coeff8.val[1], delta8.val[1], delta);
+
+               p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);
+               p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);
+               p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);
+               p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);
+            }
+
+            p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));
+            p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));
+            vst1_f32(output, vpadd_f32(p3, p4));
+            output                 += 2;
+            out_frames++;
+            resamp->time           += ratio;
+         }
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+#endif
+
+/* Assumes that taps >= 8, and that taps is a multiple of 8. */
+static void resampler_sinc_process_neon(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+
+   while (frames)
+   {
+      while (frames && resamp->time >= phases)
+      {
+         /* Push in reverse to make filter more obvious. */
+         if (!resamp->ptr)
+            resamp->ptr = taps;
+         resamp->ptr--;
+
+         resamp->buffer_l[resamp->ptr + taps] =
+            resamp->buffer_l[resamp->ptr]     = *input++;
+
+         resamp->buffer_r[resamp->ptr + taps] =
+            resamp->buffer_r[resamp->ptr]     = *input++;
+
+         resamp->time                        -= phases;
+         frames--;
+      }
+
+      {
+         const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+         const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+         while (resamp->time < phases)
+         {
+            unsigned phase           = resamp->time >> resamp->subphase_bits;
+            const float *phase_table = resamp->phase_table + phase * taps;
+#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
+            process_sinc_neon_asm(output, buffer_l, buffer_r, phase_table, taps);
+#else
+            int i;
+            float32x4_t p1 = {0, 0, 0, 0}, p2 = {0, 0, 0, 0};
+            float32x2_t p3, p4;
+
+            for (i = 0; i < (int)taps; i += 8)
+            {
+               float32x4x2_t coeff8  = vld2q_f32(&phase_table[i]);
+               float32x4x2_t left8   = vld2q_f32(&buffer_l[i]);
+               float32x4x2_t right8  = vld2q_f32(&buffer_r[i]);
+
+               p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);
+               p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);
+               p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);
+               p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);
+            }
+
+            p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));
+            p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));
+            vst1_f32(output, vpadd_f32(p3, p4));
+#endif
+            output                 += 2;
+            out_frames++;
+            resamp->time           += ratio;
+         }
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+#endif
+
+#if defined(__AVX__)
+static void resampler_sinc_process_avx_kaiser(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+
+   {
+      while (frames)
+      {
+         while (frames && resamp->time >= phases)
+         {
+            /* Push in reverse to make filter more obvious. */
+            if (!resamp->ptr)
+               resamp->ptr = taps;
+            resamp->ptr--;
+
+            resamp->buffer_l[resamp->ptr + taps] =
+               resamp->buffer_l[resamp->ptr]     = *input++;
+
+            resamp->buffer_r[resamp->ptr + taps] =
+               resamp->buffer_r[resamp->ptr]     = *input++;
+
+            resamp->time                                -= phases;
+            frames--;
+         }
+
+         {
+            const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+            const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+            while (resamp->time < phases)
+            {
+               int i;
+               unsigned phase           = resamp->time >> resamp->subphase_bits;
+
+               float *phase_table       = resamp->phase_table + phase * taps * 2;
+               float *delta_table       = phase_table + taps;
+               __m256 delta             = _mm256_set1_ps((float)
+                     (resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
+
+               __m256 sum_l             = _mm256_setzero_ps();
+               __m256 sum_r             = _mm256_setzero_ps();
+
+               for (i = 0; i < (int)taps; i += 8)
+               {
+                  __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);
+                  __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);
+                  __m256 deltas = _mm256_load_ps(delta_table + i);
+                  __m256 sinc   = _mm256_add_ps(_mm256_load_ps((const float*)phase_table + i),
+                        _mm256_mul_ps(deltas, delta));
+
+                  sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
+                  sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
+               }
+
+               /* hadd on AVX is weird, and acts on low-lanes
+                * and high-lanes separately. */
+               __m256 res_l = _mm256_hadd_ps(sum_l, sum_l);
+               __m256 res_r = _mm256_hadd_ps(sum_r, sum_r);
+               res_l        = _mm256_hadd_ps(res_l, res_l);
+               res_r        = _mm256_hadd_ps(res_r, res_r);
+               res_l        = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
+               res_r        = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);
+
+               /* This is optimized to mov %xmmN, [mem].
+                * There doesn't seem to be any _mm256_store_ss intrinsic. */
+               _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
+               _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));
+
+               output += 2;
+               out_frames++;
+               resamp->time += ratio;
+            }
+         }
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+
+static void resampler_sinc_process_avx(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+
+   {
+      while (frames)
+      {
+         while (frames && resamp->time >= phases)
+         {
+            /* Push in reverse to make filter more obvious. */
+            if (!resamp->ptr)
+               resamp->ptr = taps;
+            resamp->ptr--;
+
+            resamp->buffer_l[resamp->ptr + taps] =
+               resamp->buffer_l[resamp->ptr]     = *input++;
+
+            resamp->buffer_r[resamp->ptr + taps] =
+               resamp->buffer_r[resamp->ptr]     = *input++;
+
+            resamp->time                        -= phases;
+            frames--;
+         }
+
+         {
+            const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+            const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+            while (resamp->time < phases)
+            {
+               int i;
+               __m256 delta;
+               unsigned phase           = resamp->time >> resamp->subphase_bits;
+               float *phase_table       = resamp->phase_table + phase * taps;
+
+               __m256 sum_l             = _mm256_setzero_ps();
+               __m256 sum_r             = _mm256_setzero_ps();
+
+               for (i = 0; i < (int)taps; i += 8)
+               {
+                  __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);
+                  __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);
+                  __m256 sinc   = _mm256_load_ps((const float*)phase_table + i);
+
+                  sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
+                  sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
+               }
+
+               /* hadd on AVX is weird, and acts on low-lanes
+                * and high-lanes separately. */
+               __m256 res_l = _mm256_hadd_ps(sum_l, sum_l);
+               __m256 res_r = _mm256_hadd_ps(sum_r, sum_r);
+               res_l        = _mm256_hadd_ps(res_l, res_l);
+               res_r        = _mm256_hadd_ps(res_r, res_r);
+               res_l        = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
+               res_r        = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);
+
+               /* This is optimized to mov %xmmN, [mem].
+                * There doesn't seem to be any _mm256_store_ss intrinsic. */
+               _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
+               _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));
+
+               output += 2;
+               out_frames++;
+               resamp->time += ratio;
+            }
+         }
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+#endif
+
+#if defined(__SSE__)
+static void resampler_sinc_process_sse_kaiser(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+
+   {
+      while (frames)
+      {
+         while (frames && resamp->time >= phases)
+         {
+            /* Push in reverse to make filter more obvious. */
+            if (!resamp->ptr)
+               resamp->ptr = taps;
+            resamp->ptr--;
+
+            resamp->buffer_l[resamp->ptr + taps] =
+               resamp->buffer_l[resamp->ptr]     = *input++;
+
+            resamp->buffer_r[resamp->ptr + taps] =
+               resamp->buffer_r[resamp->ptr]     = *input++;
+
+            resamp->time                        -= phases;
+            frames--;
+         }
+
+         {
+            const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+            const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+            while (resamp->time < phases)
+            {
+               int i;
+               __m128 sum;
+               unsigned phase           = resamp->time >> resamp->subphase_bits;
+               float *phase_table       = resamp->phase_table + phase * taps * 2;
+               float *delta_table       = phase_table + taps;
+               __m128 delta             = _mm_set1_ps((float)
+                     (resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
+
+               __m128 sum_l             = _mm_setzero_ps();
+               __m128 sum_r             = _mm_setzero_ps();
+
+               for (i = 0; i < (int)taps; i += 4)
+               {
+                  __m128 buf_l = _mm_loadu_ps(buffer_l + i);
+                  __m128 buf_r = _mm_loadu_ps(buffer_r + i);
+                  __m128 deltas = _mm_load_ps(delta_table + i);
+                  __m128 _sinc  = _mm_add_ps(_mm_load_ps((const float*)phase_table + i),
+                        _mm_mul_ps(deltas, delta));
+                  sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
+                  sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
+               }
+
+               /* Them annoying shuffles.
+                * sum_l = { l3, l2, l1, l0 }
+                * sum_r = { r3, r2, r1, r0 }
+                */
+
+               sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
+                        _MM_SHUFFLE(1, 0, 1, 0)),
+                     _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));
+
+               /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
+                * sum   = { R1, R0, L1, L0 }
+                */
+
+               sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);
+
+               /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
+                * sum   = { X,  R,  X,  L }
+                */
+
+               /* Store L */
+               _mm_store_ss(output + 0, sum);
+
+               /* movehl { X, R, X, L } == { X, R, X, R } */
+               _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));
+
+               output += 2;
+               out_frames++;
+               resamp->time += ratio;
+            }
+         }
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+
+static void resampler_sinc_process_sse(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+
+   {
+      while (frames)
+      {
+         while (frames && resamp->time >= phases)
+         {
+            /* Push in reverse to make filter more obvious. */
+            if (!resamp->ptr)
+               resamp->ptr = taps;
+            resamp->ptr--;
+
+            resamp->buffer_l[resamp->ptr + taps] =
+               resamp->buffer_l[resamp->ptr]     = *input++;
+
+            resamp->buffer_r[resamp->ptr + taps] =
+               resamp->buffer_r[resamp->ptr]     = *input++;
+
+            resamp->time                        -= phases;
+            frames--;
+         }
+
+         {
+            const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+            const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+            while (resamp->time < phases)
+            {
+               int i;
+               __m128 sum;
+               unsigned phase           = resamp->time >> resamp->subphase_bits;
+               float *phase_table       = resamp->phase_table + phase * taps;
+
+               __m128 sum_l             = _mm_setzero_ps();
+               __m128 sum_r             = _mm_setzero_ps();
+
+               for (i = 0; i < (int)taps; i += 4)
+               {
+                  __m128 buf_l = _mm_loadu_ps(buffer_l + i);
+                  __m128 buf_r = _mm_loadu_ps(buffer_r + i);
+                  __m128 _sinc = _mm_load_ps((const float*)phase_table + i);
+                  sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
+                  sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
+               }
+
+               /* Them annoying shuffles.
+                * sum_l = { l3, l2, l1, l0 }
+                * sum_r = { r3, r2, r1, r0 }
+                */
+
+               sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
+                        _MM_SHUFFLE(1, 0, 1, 0)),
+                     _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));
+
+               /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
+                * sum   = { R1, R0, L1, L0 }
+                */
+
+               sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);
+
+               /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
+                * sum   = { X,  R,  X,  L }
+                */
+
+               /* Store L */
+               _mm_store_ss(output + 0, sum);
+
+               /* movehl { X, R, X, L } == { X, R, X, R } */
+               _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));
+
+               output += 2;
+               out_frames++;
+               resamp->time += ratio;
+            }
+         }
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+#endif
+
+static void resampler_sinc_process_c_kaiser(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+
+   {
+      while (frames)
+      {
+         while (frames && resamp->time >= phases)
+         {
+            /* Push in reverse to make filter more obvious. */
+            if (!resamp->ptr)
+               resamp->ptr = taps;
+            resamp->ptr--;
+
+            resamp->buffer_l[resamp->ptr + taps]    =
+               resamp->buffer_l[resamp->ptr]        = *input++;
+
+            resamp->buffer_r[resamp->ptr + taps]    =
+               resamp->buffer_r[resamp->ptr]        = *input++;
+
+            resamp->time                           -= phases;
+            frames--;
+         }
+
+         {
+            const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+            const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+            while (resamp->time < phases)
+            {
+               int i;
+               float sum_l              = 0.0f;
+               float sum_r              = 0.0f;
+               unsigned phase           = resamp->time >> resamp->subphase_bits;
+               float *phase_table       = resamp->phase_table + phase * taps * 2;
+               float *delta_table       = phase_table + taps;
+               float delta              = (float)
+                  (resamp->time & resamp->subphase_mask) * resamp->subphase_mod;
+
+               for (i = 0; i < (int)taps; i++)
+               {
+                  float sinc_val        = phase_table[i] + delta_table[i] * delta;
+
+                  sum_l                += buffer_l[i] * sinc_val;
+                  sum_r                += buffer_r[i] * sinc_val;
+               }
+
+               output[0]                = sum_l;
+               output[1]                = sum_r;
+
+               output                  += 2;
+               out_frames++;
+               resamp->time            += ratio;
+            }
+         }
+
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+
+static void resampler_sinc_process_c(void *re_, struct resampler_data *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;
+   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);
+
+   uint32_t ratio                 = phases / data->ratio;
+   const float *input             = data->data_in;
+   float *output                  = data->data_out;
+   size_t frames                  = data->input_frames;
+   size_t out_frames              = 0;
+   unsigned taps                  = resamp->taps;
+
+   {
+      while (frames)
+      {
+         while (frames && resamp->time >= phases)
+         {
+            /* Push in reverse to make filter more obvious. */
+            if (!resamp->ptr)
+               resamp->ptr = taps;
+            resamp->ptr--;
+
+            resamp->buffer_l[resamp->ptr + taps]    =
+               resamp->buffer_l[resamp->ptr]        = *input++;
+
+            resamp->buffer_r[resamp->ptr + taps]    =
+               resamp->buffer_r[resamp->ptr]        = *input++;
+
+            resamp->time                           -= phases;
+            frames--;
+         }
+
+         {
+            const float *buffer_l    = resamp->buffer_l + resamp->ptr;
+            const float *buffer_r    = resamp->buffer_r + resamp->ptr;
+            while (resamp->time < phases)
+            {
+               int i;
+               float sum_l              = 0.0f;
+               float sum_r              = 0.0f;
+               unsigned phase           = resamp->time >> resamp->subphase_bits;
+               float *phase_table       = resamp->phase_table + phase * taps;
+
+               for (i = 0; i < (int)taps; i++)
+               {
+                  float sinc_val        = phase_table[i];
+
+                  sum_l                += buffer_l[i] * sinc_val;
+                  sum_r                += buffer_r[i] * sinc_val;
+               }
+
+               output[0]                = sum_l;
+               output[1]                = sum_r;
+
+               output                  += 2;
+               out_frames++;
+               resamp->time            += ratio;
+            }
+         }
+
+      }
+   }
+
+   data->output_frames = out_frames;
+}
+
+static void resampler_sinc_free(void *data)
+{
+   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)data;
+   if (resamp)
+      memalign_free(resamp->main_buffer);
+   free(resamp);
+}
+
+static void sinc_init_table_kaiser(rarch_sinc_resampler_t *resamp,
+      double cutoff,
+      float *phase_table, int phases, int taps, bool calculate_delta)
+{
+   int i, j;
+   /* Kaiser window function - need to normalize w(0) to 1.0f */
+   float kaiser_beta    = resamp->kaiser_beta;
+   double    window_mod = besseli0(kaiser_beta);
+   int           stride = calculate_delta ? 2 : 1;
+   double     sidelobes = taps / 2.0;
+
+   for (i = 0; i < phases; i++)
+   {
+      for (j = 0; j < taps; j++)
+      {
+         float val;
+         double sinc_phase;
+         int               n = j * phases + i;
+         double window_phase = (double)n / (phases * taps); /* [0, 1). */
+         window_phase        = 2.0 * window_phase - 1.0; /* [-1, 1) */
+         sinc_phase          = sidelobes * window_phase;
+         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
+              besseli0(kaiser_beta * sqrtf(1 - window_phase * window_phase))
+            / window_mod;
+         phase_table[i * stride * taps + j] = val;
+      }
+   }
+
+   if (calculate_delta)
+   {
+      int phase;
+      int p;
+
+      for (p = 0; p < phases - 1; p++)
+      {
+         for (j = 0; j < taps; j++)
+         {
+            float delta = phase_table[(p + 1) * stride * taps + j] -
+               phase_table[p * stride * taps + j];
+            phase_table[(p * stride + 1) * taps + j] = delta;
+         }
+      }
+
+      phase = phases - 1;
+      for (j = 0; j < taps; j++)
+      {
+         float val, delta;
+         double sinc_phase;
+         int n               = j * phases + (phase + 1);
+         double window_phase = (double)n / (phases * taps); /* (0, 1]. */
+         window_phase        = 2.0 * window_phase - 1.0; /* (-1, 1] */
+         sinc_phase          = sidelobes * window_phase;
+
+         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
+              besseli0(resamp->kaiser_beta * sqrtf(1 - window_phase *
+window_phase)) / window_mod;
+         delta = (val - phase_table[phase * stride * taps + j]);
+         phase_table[(phase * stride + 1) * taps + j] = delta;
+      }
+   }
+}
+
+static void sinc_init_table_lanczos(
+      rarch_sinc_resampler_t *resamp, double cutoff,
+      float *phase_table, int phases, int taps, bool calculate_delta)
+{
+   int i, j;
+   /* Lanczos window function - need to normalize w(0) to 1.0f */
+   double    window_mod = 1.0;
+   int           stride = calculate_delta ? 2 : 1;
+   double     sidelobes = taps / 2.0;
+
+   for (i = 0; i < phases; i++)
+   {
+      for (j = 0; j < taps; j++)
+      {
+         double sinc_phase;
+         float val;
+         int               n = j * phases + i;
+         double window_phase = (double)n / (phases * taps); /* [0, 1). */
+         window_phase        = 2.0 * window_phase - 1.0; /* [-1, 1) */
+         sinc_phase          = sidelobes * window_phase;
+         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
+            sinc(M_PI * window_phase) / window_mod;
+         phase_table[i * stride * taps + j] = val;
+      }
+   }
+
+   if (calculate_delta)
+   {
+      int phase;
+      int p;
+
+      for (p = 0; p < phases - 1; p++)
+      {
+         for (j = 0; j < taps; j++)
+         {
+            float delta = phase_table[(p + 1) * stride * taps + j] -
+               phase_table[p * stride * taps + j];
+            phase_table[(p * stride + 1) * taps + j] = delta;
+         }
+      }
+
+      phase = phases - 1;
+      for (j = 0; j < taps; j++)
+      {
+         float val, delta;
+         double sinc_phase;
+         int n               = j * phases + (phase + 1);
+         double window_phase = (double)n / (phases * taps); /* (0, 1]. */
+         window_phase        = 2.0 * window_phase - 1.0; /* (-1, 1] */
+         sinc_phase          = sidelobes * window_phase;
+
+         val                 = cutoff * sinc(M_PI * sinc_phase * cutoff) *
+            sinc(M_PI * window_phase) / window_mod;
+         delta = (val - phase_table[phase * stride * taps + j]);
+         phase_table[(phase * stride + 1) * taps + j] = delta;
+      }
+   }
+}
+
+static void *resampler_sinc_new(const struct resampler_config *config,
+      double bandwidth_mod, enum resampler_quality quality,
+      resampler_simd_mask_t mask)
+{
+   double cutoff                  = 0.0;
+   size_t phase_elems             = 0;
+   size_t elems                   = 0;
+   unsigned enable_avx            = 0;
+   unsigned sidelobes             = 0;
+   enum sinc_window window_type   = SINC_WINDOW_NONE;
+   rarch_sinc_resampler_t *re     = (rarch_sinc_resampler_t*)
+      calloc(1, sizeof(*re));
+
+   if (!re)
+      return NULL;
+
+   switch (quality)
+   {
+      case RESAMPLER_QUALITY_LOWEST:
+         cutoff            = 0.98;
+         sidelobes         = 2;
+         re->phase_bits    = 12;
+         re->subphase_bits = 10;
+         window_type       = SINC_WINDOW_LANCZOS;
+         break;
+      case RESAMPLER_QUALITY_LOWER:
+         cutoff            = 0.98;
+         sidelobes         = 4;
+         re->phase_bits    = 12;
+         re->subphase_bits = 10;
+         window_type       = SINC_WINDOW_LANCZOS;
+         break;
+      case RESAMPLER_QUALITY_HIGHER:
+         cutoff            = 0.90;
+         sidelobes         = 32;
+         re->phase_bits    = 10;
+         re->subphase_bits = 14;
+         window_type       = SINC_WINDOW_KAISER;
+         re->kaiser_beta   = 10.5;
+         enable_avx        = 1;
+         break;
+      case RESAMPLER_QUALITY_HIGHEST:
+         cutoff            = 0.962;
+         sidelobes         = 128;
+         re->phase_bits    = 10;
+         re->subphase_bits = 14;
+         window_type       = SINC_WINDOW_KAISER;
+         re->kaiser_beta   = 14.5;
+         enable_avx        = 1;
+         break;
+      case RESAMPLER_QUALITY_NORMAL:
+      case RESAMPLER_QUALITY_DONTCARE:
+         cutoff            = 0.825;
+         sidelobes         = 8;
+         re->phase_bits    = 8;
+         re->subphase_bits = 16;
+         window_type       = SINC_WINDOW_KAISER;
+         re->kaiser_beta   = 5.5;
+         break;
+   }
+
+   re->subphase_mask = (1 << re->subphase_bits) - 1;
+   re->subphase_mod  = 1.0f / (1 << re->subphase_bits);
+   re->taps          = sidelobes * 2;
+
+   /* Downsampling, must lower cutoff, and extend number of
+    * taps accordingly to keep same stopband attenuation. */
+   if (bandwidth_mod < 1.0)
+   {
+      cutoff  *= bandwidth_mod;
+      re->taps = (unsigned)ceil(re->taps / bandwidth_mod);
+   }
+
+   /* Be SIMD-friendly. */
+#if defined(__AVX__)
+   if (enable_avx)
+      re->taps  = (re->taps + 7) & ~7;
+   else
+#endif
+   {
+#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
+      re->taps     = (re->taps + 7) & ~7;
+#else
+      re->taps     = (re->taps + 3) & ~3;
+#endif
+   }
+
+   phase_elems     = ((1 << re->phase_bits) * re->taps);
+   if (window_type == SINC_WINDOW_KAISER)
+      phase_elems  = phase_elems * 2;
+   elems           = phase_elems + 4 * re->taps;
+
+   re->main_buffer = (float*)memalign_alloc(128, sizeof(float) * elems);
+   if (!re->main_buffer)
+      goto error;
+
+   memset(re->main_buffer, 0, sizeof(float) * elems);
+
+   re->phase_table = re->main_buffer;
+   re->buffer_l    = re->main_buffer + phase_elems;
+   re->buffer_r    = re->buffer_l + 2 * re->taps;
+
+   switch (window_type)
+   {
+      case SINC_WINDOW_LANCZOS:
+         sinc_init_table_lanczos(re, cutoff, re->phase_table,
+               1 << re->phase_bits, re->taps, false);
+         break;
+      case SINC_WINDOW_KAISER:
+         sinc_init_table_kaiser(re, cutoff, re->phase_table,
+               1 << re->phase_bits, re->taps, true);
+         break;
+      case SINC_WINDOW_NONE:
+         goto error;
+   }
+
+   sinc_resampler.process = resampler_sinc_process_c;
+   if (window_type == SINC_WINDOW_KAISER)
+      sinc_resampler.process    = resampler_sinc_process_c_kaiser;
+
+   if (mask & RESAMPLER_SIMD_AVX && enable_avx)
+   {
+#if defined(__AVX__)
+      sinc_resampler.process    = resampler_sinc_process_avx;
+      if (window_type == SINC_WINDOW_KAISER)
+         sinc_resampler.process = resampler_sinc_process_avx_kaiser;
+#endif
+   }
+   else if (mask & RESAMPLER_SIMD_SSE)
+   {
+#if defined(__SSE__)
+      sinc_resampler.process = resampler_sinc_process_sse;
+      if (window_type == SINC_WINDOW_KAISER)
+         sinc_resampler.process = resampler_sinc_process_sse_kaiser;
+#endif
+   }
+   else if (mask & RESAMPLER_SIMD_NEON)
+   {
+#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
+#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS
+      if (window_type != SINC_WINDOW_KAISER)
+         sinc_resampler.process = resampler_sinc_process_neon;
+#else
+      sinc_resampler.process = resampler_sinc_process_neon;
+      if (window_type == SINC_WINDOW_KAISER)
+         sinc_resampler.process = resampler_sinc_process_neon_kaiser;
+#endif
+#endif
+   }
+
+   return re;
+
+error:
+   resampler_sinc_free(re);
+   return NULL;
+}
+
+retro_resampler_t sinc_resampler = {
+   resampler_sinc_new,
+   resampler_sinc_process_c,
+   resampler_sinc_free,
+   RESAMPLER_API_VERSION,
+   "sinc",
+   "sinc"
+};
diff --git a/deps/libretro-common/audio/resampler/drivers/sinc_resampler_neon.S b/deps/libretro-common/audio/resampler/drivers/sinc_resampler_neon.S
new file mode 100644 (file)
index 0000000..c9587fd
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (sinc_resampler_neon.S).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)
+
+#ifndef __MACH__
+.arm
+#endif
+.align 4
+.globl process_sinc_neon_asm
+#ifndef __MACH__
+.type process_sinc_neon_asm, %function
+#endif
+.globl _process_sinc_neon_asm
+#ifndef __MACH__
+.type _process_sinc_neon_asm, %function
+#endif
+# void process_sinc_neon(float *out, const float *left, const float *right, const float *coeff, unsigned taps)
+# Assumes taps is >= 8, and a multiple of 8.
+process_sinc_neon_asm:
+_process_sinc_neon_asm:
+
+   push {r4, lr}
+   vmov.f32 q0, #0.0
+   vmov.f32 q8, #0.0
+
+   # Taps argument (r4) goes on stack in armeabi.
+   ldr r4, [sp, #8]
+
+1:
+   # Left
+   vld1.f32 {q2-q3}, [r1]!
+   # Right
+   vld1.f32 {q10-q11}, [r2]!
+   # Coeff
+   vld1.f32 {q12-q13}, [r3, :128]!
+
+   # Left / Right
+   vmla.f32 q0, q2, q12
+   vmla.f32 q8, q10, q12
+   vmla.f32 q0, q3, q13
+   vmla.f32 q8, q11, q13
+
+   subs r4, r4, #8
+   bne 1b
+
+   # Add everything together
+   vadd.f32 d0, d0, d1
+   vadd.f32 d16, d16, d17
+   vpadd.f32 d0, d0, d16
+   vst1.f32 d0, [r0]
+
+   pop {r4, pc}
+
+#endif
diff --git a/deps/libretro-common/cdrom/cdrom.c b/deps/libretro-common/cdrom/cdrom.c
new file mode 100644 (file)
index 0000000..56c8f2a
--- /dev/null
@@ -0,0 +1,1730 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (cdrom.c).
+* ---------------------------------------------------------------------------------------
+*
+* 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <cdrom/cdrom.h>
+#include <libretro.h>
+#include <stdio.h>
+#include <string.h>
+#include <compat/strl.h>
+#include <compat/strcasestr.h>
+#include <retro_math.h>
+#include <retro_timers.h>
+#include <streams/file_stream.h>
+#include <retro_endianness.h>
+#include <retro_miscellaneous.h>
+#include <vfs/vfs_implementation.h>
+#include <lists/string_list.h>
+#include <lists/dir_list.h>
+#include <string/stdstring.h>
+#include <memalign.h>
+
+#include <math.h>
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#if defined(__linux__) && !defined(ANDROID)
+#include <sys/ioctl.h>
+#include <scsi/sg.h>
+#endif
+
+#if defined(_WIN32) && !defined(_XBOX)
+#include <windows.h>
+#include <winioctl.h>
+#include <ntddscsi.h>
+#endif
+
+#define CDROM_CUE_TRACK_BYTES 107
+#define CDROM_MAX_SENSE_BYTES 16
+#define CDROM_MAX_RETRIES 10
+
+typedef enum
+{
+   DIRECTION_NONE,
+   DIRECTION_IN,
+   DIRECTION_OUT
+} CDROM_CMD_Direction;
+
+void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame)
+{
+   if (!min || !sec || !frame)
+      return;
+
+   *frame = lba % 75;
+   lba /= 75;
+   *sec = lba % 60;
+   lba /= 60;
+   *min = lba;
+}
+
+unsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame)
+{
+   return (min * 60 + sec) * 75 + frame;
+}
+
+void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
+{
+   if (!min || !sec || !frame)
+      return;
+
+   *min = (*frame == 74) ? (*sec < 59 ? *min : *min + 1) : *min;
+   *sec = (*frame == 74) ? (*sec < 59 ? (*sec + 1) : 0) : *sec;
+   *frame = (*frame < 74) ? (*frame + 1) : 0;
+}
+
+#ifdef CDROM_DEBUG
+static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
+{
+   unsigned i;
+   const char *sense_key_text = NULL;
+   unsigned char key;
+   unsigned char asc;
+   unsigned char ascq;
+
+   if (len < 16)
+   {
+      printf("[CDROM] Sense data buffer length too small.\n");
+      fflush(stdout);
+      return;
+   }
+
+   key = sense[2] & 0xF;
+   asc = sense[12];
+   ascq = sense[13];
+
+   printf("[CDROM] Sense Data: ");
+
+   for (i = 0; i < MIN(len, 16); i++)
+   {
+      printf("%02X ", sense[i]);
+   }
+
+   printf("\n");
+
+   if (sense[0] == 0x70)
+      printf("[CDROM] CURRENT ERROR:\n");
+   if (sense[0] == 0x71)
+      printf("[CDROM] DEFERRED ERROR:\n");
+
+   switch (key)
+   {
+      case 0:
+         sense_key_text = "NO SENSE";
+         break;
+      case 1:
+         sense_key_text = "RECOVERED ERROR";
+         break;
+      case 2:
+         sense_key_text = "NOT READY";
+         break;
+      case 3:
+         sense_key_text = "MEDIUM ERROR";
+         break;
+      case 4:
+         sense_key_text = "HARDWARE ERROR";
+         break;
+      case 5:
+         sense_key_text = "ILLEGAL REQUEST";
+         break;
+      case 6:
+         sense_key_text = "UNIT ATTENTION";
+         break;
+      case 7:
+         sense_key_text = "DATA PROTECT";
+         break;
+      case 8:
+         sense_key_text = "BLANK CHECK";
+         break;
+      case 9:
+         sense_key_text = "VENDOR SPECIFIC";
+         break;
+      case 10:
+         sense_key_text = "COPY ABORTED";
+         break;
+      case 11:
+         sense_key_text = "ABORTED COMMAND";
+         break;
+      case 13:
+         sense_key_text = "VOLUME OVERFLOW";
+         break;
+      case 14:
+         sense_key_text = "MISCOMPARE";
+         break;
+   }
+
+   printf("[CDROM] Sense Key: %02X (%s)\n", key, sense_key_text ? sense_key_text : "null");
+   printf("[CDROM] ASC: %02X\n", asc);
+   printf("[CDROM] ASCQ: %02X\n", ascq);
+
+   switch (key)
+   {
+      case 2:
+      {
+         switch (asc)
+         {
+            case 4:
+            {
+               switch (ascq)
+               {
+                  case 1:
+                     printf("[CDROM] Description: LOGICAL UNIT IS IN PROCESS OF BECOMING READY\n");
+                     break;
+                  default:
+                     break;
+               }
+
+               break;
+            }
+            case 0x3a:
+            {
+               switch (ascq)
+               {
+                  case 0:
+                     printf("[CDROM] Description: MEDIUM NOT PRESENT\n");
+                     break;
+                  case 3:
+                     printf("[CDROM] Description: MEDIUM NOT PRESENT - LOADABLE\n");
+                     break;
+                  case 1:
+                     printf("[CDROM] Description: MEDIUM NOT PRESENT - TRAY CLOSED\n");
+                     break;
+                  case 2:
+                     printf("[CDROM] Description: MEDIUM NOT PRESENT - TRAY OPEN\n");
+                     break;
+                  default:
+                     break;
+               }
+
+               break;
+            }
+            default:
+               break;
+         }
+      }
+      case 3:
+      {
+         if (asc == 0x11 && ascq == 0x5)
+            printf("[CDROM] Description: L-EC UNCORRECTABLE ERROR\n");
+         break;
+      }
+      case 5:
+      {
+         if (asc == 0x20 && ascq == 0)
+            printf("[CDROM] Description: INVALID COMMAND OPERATION CODE\n");
+         else if (asc == 0x24 && ascq == 0)
+            printf("[CDROM] Description: INVALID FIELD IN CDB\n");
+         else if (asc == 0x26 && ascq == 0)
+            printf("[CDROM] Description: INVALID FIELD IN PARAMETER LIST\n");
+         break;
+      }
+      case 6:
+      {
+         if (asc == 0x28 && ascq == 0)
+            printf("[CDROM] Description: NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED\n");
+         break;
+      }
+      default:
+         break;
+   }
+
+   fflush(stdout);
+}
+#endif
+
+#if defined(_WIN32) && !defined(_XBOX)
+static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
+{
+   DWORD ioctl_bytes;
+   BOOL ioctl_rv;
+#ifdef CDROM_DEBUG
+   clock_t t = clock();
+   const char *extra = " ";
+   static unsigned char last_min = 0;
+   static unsigned char last_sec = 0;
+   static unsigned char last_frame = 0;
+
+   unsigned lba_cur = cdrom_msf_to_lba(last_min, last_sec, last_frame);
+   unsigned lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);
+#endif
+   struct sptd_with_sense
+   {
+     SCSI_PASS_THROUGH_DIRECT s;
+     UCHAR sense[128];
+   } sptd;
+
+   memset(&sptd, 0, sizeof(sptd));
+
+   sptd.s.Length = sizeof(sptd.s);
+   sptd.s.CdbLength = cmd_len;
+
+   switch (dir)
+   {
+      case DIRECTION_IN:
+         sptd.s.DataIn = SCSI_IOCTL_DATA_IN;
+         break;
+      case DIRECTION_OUT:
+         sptd.s.DataIn = SCSI_IOCTL_DATA_OUT;
+         break;
+      case DIRECTION_NONE:
+      default:
+         sptd.s.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;
+         break;
+   }
+
+   sptd.s.TimeOutValue = 5;
+   sptd.s.DataBuffer = buf;
+   sptd.s.DataTransferLength = len;
+   sptd.s.SenseInfoLength = sizeof(sptd.sense);
+   sptd.s.SenseInfoOffset = offsetof(struct sptd_with_sense, sense);
+
+   memcpy(sptd.s.Cdb, cmd, cmd_len);
+
+   ioctl_rv = DeviceIoControl(stream->fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd,
+      sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL);
+
+#ifdef CDROM_DEBUG
+   if (lba_req < lba_cur)
+      extra = " BACKWARDS SECTOR READ";
+   else if (lba_req > lba_cur)
+      extra = " SKIPPED SECTOR READ";
+
+   if (cmd[0] == 0xB9)
+   {
+      double time_taken = (double)(((clock() - t) * 1000) / CLOCKS_PER_SEC);
+      printf("time taken %f ms for DT received length %ld of %" PRId64 " for %02d:%02d:%02d to %02d:%02d:%02d%s req %d cur %d cur_lba %d\n", time_taken, sptd.s.DataTransferLength, len, cmd[3], cmd[4], cmd[5], cmd[6], cmd[7], cmd[8], extra, lba_req, lba_cur, stream->cdrom.cur_lba);
+      fflush(stdout);
+   }
+
+   last_min = cmd[3];
+   last_sec = cmd[4];
+   last_frame = cmd[5];
+   increment_msf(&last_min, &last_sec, &last_frame);
+#endif
+
+   if (!ioctl_rv || sptd.s.ScsiStatus != 0)
+      return 1;
+
+   return 0;
+}
+#endif
+
+#if defined(__linux__) && !defined(ANDROID)
+static int cdrom_send_command_linux(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
+{
+   sg_io_hdr_t sgio = {0};
+   int rv;
+
+   switch (dir)
+   {
+      case DIRECTION_IN:
+         sgio.dxfer_direction = SG_DXFER_FROM_DEV;
+         break;
+      case DIRECTION_OUT:
+         sgio.dxfer_direction = SG_DXFER_TO_DEV;
+         break;
+      case DIRECTION_NONE:
+      default:
+         sgio.dxfer_direction = SG_DXFER_NONE;
+         break;
+   }
+
+   sgio.interface_id = 'S';
+   sgio.cmd_len = cmd_len;
+   sgio.cmdp = cmd;
+   sgio.dxferp = buf;
+   sgio.dxfer_len = len;
+   sgio.sbp = sense;
+   sgio.mx_sb_len = sense_len;
+   sgio.timeout = 5000;
+
+   rv = ioctl(fileno(stream->fp), SG_IO, &sgio);
+
+   if (rv == -1 || sgio.info & SG_INFO_CHECK)
+      return 1;
+
+   return 0;
+}
+#endif
+
+static int cdrom_send_command(libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, size_t skip)
+{
+   unsigned char *xfer_buf = NULL;
+   unsigned char *xfer_buf_pos = xfer_buf;
+   unsigned char sense[CDROM_MAX_SENSE_BYTES] = {0};
+   unsigned char retries_left = CDROM_MAX_RETRIES;
+   int i, rv = 0;
+   int frames = 1;
+   size_t padded_req_bytes;
+   size_t copied_bytes = 0;
+   bool read_cd = false;
+
+   if (!cmd || cmd_len == 0)
+      return 1;
+
+   if (cmd[0] == 0xBE || cmd[0] == 0xB9)
+   {
+      frames = ceil((len + skip) / 2352.0);
+      padded_req_bytes = 2352 * frames;
+      read_cd = true;
+      /* these will be incremented below */
+      cmd[6] = cmd[3];
+      cmd[7] = cmd[4];
+      cmd[8] = cmd[5];
+   }
+   else
+   {
+      padded_req_bytes = len + skip;
+   }
+
+   xfer_buf = (unsigned char*)memalign_alloc(4096, padded_req_bytes);
+   xfer_buf_pos = xfer_buf;
+
+   if (!xfer_buf)
+      return 1;
+
+   memset(xfer_buf, 0, padded_req_bytes);
+#ifdef CDROM_DEBUG
+   printf("Number of frames to read: %d\n", frames);
+   fflush(stdout);
+#endif
+   for (i = 0; i < frames; i++)
+   {
+      size_t request_len = padded_req_bytes;
+      size_t copy_len = request_len;
+      bool cached_read = false;
+
+      if (read_cd)
+      {
+         unsigned lba_req = 0;
+
+         request_len = 2352;
+         copy_len = request_len;
+
+         increment_msf(&cmd[6], &cmd[7], &cmd[8]);
+
+         if (i > 0)
+         {
+            skip = 0;
+            increment_msf(&cmd[3], &cmd[4], &cmd[5]);
+         }
+         else
+         {
+            if (skip)
+               copy_len -= skip;
+         }
+
+         if (i == frames - 1)
+         {
+            copy_len = len - copied_bytes;
+         }
+
+         lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);
+
+         if (stream->cdrom.last_frame_valid && lba_req == stream->cdrom.last_frame_lba)
+         {
+            /* use cached frame */
+            cached_read = true;
+#ifdef CDROM_DEBUG
+            printf("[CDROM] Using cached frame\n");
+            fflush(stdout);
+#endif
+            /* assumes request_len is always equal to the size of last_frame */
+            memcpy(xfer_buf_pos, stream->cdrom.last_frame, sizeof(stream->cdrom.last_frame));
+         }
+
+      }
+
+#ifdef CDROM_DEBUG
+      if (!cached_read)
+      {
+         unsigned j;
+
+         printf("[CDROM] Send Command: ");
+
+         for (j = 0; j < cmd_len / sizeof(*cmd); j++)
+         {
+            printf("%02X ", cmd[j]);
+         }
+
+         if (len)
+            printf("(buffer of size %" PRId64 " with skip bytes %" PRId64 " padded to %" PRId64 "), frame %d\n", len, skip, padded_req_bytes, i);
+         else
+            printf("\n");
+
+         fflush(stdout);
+      }
+#endif
+
+retry:
+#if defined(__linux__) && !defined(ANDROID)
+      if (cached_read || !cdrom_send_command_linux(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))
+#else
+#if defined(_WIN32) && !defined(_XBOX)
+      if (cached_read || !cdrom_send_command_win32(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))
+#endif
+#endif
+      {
+         rv = 0;
+
+         if (buf)
+         {
+#if 0
+            printf("offsetting %" PRId64 " from buf, copying at xfer_buf offset %" PRId64 ", copying %" PRId64 " bytes\n", copied_bytes, (xfer_buf_pos + skip) - xfer_buf, copy_len);
+            fflush(stdout);
+#endif
+            memcpy((char*)buf + copied_bytes, xfer_buf_pos + skip, copy_len);
+            copied_bytes += copy_len;
+
+            if (read_cd && !cached_read && request_len >= 2352)
+            {
+               unsigned frame_end = cdrom_msf_to_lba(cmd[6], cmd[7], cmd[8]);
+
+               /* cache the last received frame */
+               memcpy(stream->cdrom.last_frame, xfer_buf_pos, sizeof(stream->cdrom.last_frame));
+               stream->cdrom.last_frame_valid = true;
+               /* the ending frame is never actually read, so what we really just read is the one right before that */
+               stream->cdrom.last_frame_lba = frame_end - 1;
+            }
+            else
+               stream->cdrom.last_frame_valid = false;
+
+#if 0
+            printf("Frame %d, adding %" PRId64 " to buf_pos, is now %" PRId64 ". skip is %" PRId64 "\n", i, request_len, (xfer_buf_pos + request_len) - xfer_buf, skip);
+            fflush(stdout);
+#endif
+            xfer_buf_pos += request_len;
+         }
+      }
+      else
+      {
+#ifdef CDROM_DEBUG
+         cdrom_print_sense_data(sense, sizeof(sense));
+#endif
+
+         /* INQUIRY/TEST/SENSE should never fail, don't retry. */
+         /* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */
+         if (cmd[0] != 0x0 && cmd[0] != 0x12 && cmd[0] != 0x5A && !(cmd[0] == 0x43 && cmd[2] == 0x4))
+         {
+            unsigned char key = sense[2] & 0xF;
+
+            switch (key)
+            {
+               case 0:
+               case 2:
+               case 3:
+               case 4:
+               case 6:
+                  if (retries_left)
+                  {
+   #ifdef CDROM_DEBUG
+                     printf("[CDROM] Read Retry...\n");
+                     fflush(stdout);
+   #endif
+                     retries_left--;
+                      retro_sleep(1000);
+                     goto retry;
+                  }
+                  else
+                  {
+                     rv = 1;
+   #ifdef CDROM_DEBUG
+                     printf("[CDROM] Read retries failed, giving up.\n");
+                     fflush(stdout);
+   #endif
+                  }
+
+                  break;
+               default:
+                  break;
+            }
+         }
+
+         rv = 1;
+      }
+   }
+
+   if (xfer_buf)
+      memalign_free(xfer_buf);
+
+   return rv;
+}
+
+static const char* get_profile(unsigned short profile)
+{
+   switch (profile)
+   {
+      case 2:
+         return "Removable disk";
+         break;
+      case 8:
+         return "CD-ROM";
+         break;
+      case 9:
+         return "CD-R";
+         break;
+      case 0xA:
+         return "CD-RW";
+         break;
+      case 0x10:
+         return "DVD-ROM";
+         break;
+      case 0x11:
+         return "DVD-R Sequential Recording";
+         break;
+      case 0x12:
+         return "DVD-RAM";
+         break;
+      case 0x13:
+         return "DVD-RW Restricted Overwrite";
+         break;
+      case 0x14:
+         return "DVD-RW Sequential recording";
+         break;
+      case 0x15:
+         return "DVD-R Dual Layer Sequential Recording";
+         break;
+      case 0x16:
+         return "DVD-R Dual Layer Jump Recording";
+         break;
+      case 0x17:
+         return "DVD-RW Dual Layer";
+         break;
+      case 0x1A:
+         return "DVD+RW";
+         break;
+      case 0x1B:
+         return "DVD+R";
+         break;
+      case 0x2A:
+         return "DVD+RW Dual Layer";
+         break;
+      case 0x2B:
+         return "DVD+R Dual Layer";
+         break;
+      case 0x40:
+         return "BD-ROM";
+         break;
+      case 0x41:
+         return "BD-R SRM";
+         break;
+      case 0x42:
+         return "BD-R RRM";
+         break;
+      case 0x43:
+         return "BD-RE";
+         break;
+      case 0x50:
+         return "HD DVD-ROM";
+         break;
+      case 0x51:
+         return "HD DVD-R";
+         break;
+      case 0x52:
+         return "HD DVD-RAM";
+         break;
+      case 0x53:
+         return "HD DVD-RW";
+         break;
+      case 0x58:
+         return "HD DVD-R Dual Layer";
+         break;
+      case 0x5A:
+         return "HD DVD-RW Dual Layer";
+         break;
+      default:
+         break;
+   }
+
+   return "Unknown";
+}
+
+int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len)
+{
+   unsigned char cdb[] = {0x3, 0, 0, 0, 0xFC, 0};
+   unsigned char buf[0xFC] = {0};
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] get sense data status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return 1;
+
+#ifdef CDROM_DEBUG
+   cdrom_print_sense_data(buf, sizeof(buf));
+#endif
+
+   return 0;
+}
+
+void cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream)
+{
+   unsigned char cdb[] = {0x46, 0x2, 0, 0x10, 0, 0, 0, 0, 0x14, 0};
+   unsigned char buf[0x14] = {0};
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+   int i;
+
+   printf("[CDROM] get current config random readable status code %d\n", rv);
+
+   if (rv)
+      return;
+
+   printf("[CDROM] Feature Header: ");
+
+   for (i = 0; i < 8; i++)
+   {
+      printf("%02X ", buf[i]);
+   }
+
+   printf("\n");
+
+   printf("[CDROM] Random Readable Feature Descriptor: ");
+
+   for (i = 0; i < 12; i++)
+   {
+      printf("%02X ", buf[8 + i]);
+   }
+
+   printf("\n");
+
+   printf("[CDROM] Supported commands: READ CAPACITY, READ (10)\n");
+}
+
+void cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream)
+{
+   unsigned char cdb[] = {0x46, 0x2, 0, 0x1D, 0, 0, 0, 0, 0xC, 0};
+   unsigned char buf[0xC] = {0};
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+   int i;
+
+   printf("[CDROM] get current config multi-read status code %d\n", rv);
+
+   if (rv)
+      return;
+
+   printf("[CDROM] Feature Header: ");
+
+   for (i = 0; i < 8; i++)
+   {
+      printf("%02X ", buf[i]);
+   }
+
+   printf("\n");
+
+   printf("[CDROM] Multi-Read Feature Descriptor: ");
+
+   for (i = 0; i < 4; i++)
+   {
+      printf("%02X ", buf[8 + i]);
+   }
+
+   printf("\n");
+
+   printf("[CDROM] Supported commands: READ (10), READ CD, READ DISC INFORMATION, READ TRACK INFORMATION\n");
+}
+
+void cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream)
+{
+   unsigned char cdb[] = {0x46, 0x2, 0, 0x1E, 0, 0, 0, 0, 0x10, 0};
+   unsigned char buf[0x10] = {0};
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+   int i;
+
+   printf("[CDROM] get current config cd read status code %d\n", rv);
+
+   if (rv)
+      return;
+
+   printf("[CDROM] Feature Header: ");
+
+   for (i = 0; i < 8; i++)
+   {
+      printf("%02X ", buf[i]);
+   }
+
+   printf("\n");
+
+   printf("[CDROM] CD Read Feature Descriptor: ");
+
+   for (i = 0; i < 8; i++)
+   {
+      printf("%02X ", buf[8 + i]);
+   }
+
+   if (buf[8 + 2] & 1)
+      printf("(current)\n");
+
+   printf("[CDROM] Supported commands: READ CD, READ CD MSF, READ TOC/PMA/ATIP\n");
+}
+
+void cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream)
+{
+   unsigned char cdb[] = {0x46, 0x2, 0, 0x0, 0, 0, 0, 0xFF, 0xFA, 0};
+   unsigned char buf[0xFFFA] = {0};
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+   int i;
+
+   printf("[CDROM] get current config profiles status code %d\n", rv);
+
+   if (rv)
+      return;
+
+   printf("[CDROM] Feature Header: ");
+
+   for (i = 0; i < 8; i++)
+   {
+      printf("%02X ", buf[i]);
+   }
+
+   printf("\n");
+
+   printf("[CDROM] Profile List Descriptor: ");
+
+   for (i = 0; i < 4; i++)
+   {
+      printf("%02X ", buf[8 + i]);
+   }
+
+   printf("\n");
+
+   printf("[CDROM] Number of profiles: %u\n", buf[8 + 3] / 4);
+
+   for (i = 0; i < buf[8 + 3] / 4; i++)
+   {
+      unsigned short profile = (buf[8 + (4 * (i + 1))] << 8) | buf[8 + (4 * (i + 1)) + 1];
+
+      printf("[CDROM] Profile Number: %04X (%s) ", profile, get_profile(profile));
+
+      if (buf[8 + (4 * (i + 1)) + 2] & 1)
+         printf("(current)\n");
+      else
+         printf("\n");
+   }
+}
+
+void cdrom_get_current_config_core(libretro_vfs_implementation_file *stream)
+{
+   unsigned char cdb[] = {0x46, 0x2, 0, 0x1, 0, 0, 0, 0, 0x14, 0};
+   unsigned char buf[20] = {0};
+   unsigned intf_std = 0;
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+   int i;
+   const char *intf_std_name = "Unknown";
+
+   printf("[CDROM] get current config core status code %d\n", rv);
+
+   if (rv)
+      return;
+
+   printf("[CDROM] Feature Header: ");
+
+   for (i = 0; i < 8; i++)
+   {
+      printf("%02X ", buf[i]);
+   }
+
+   printf("\n");
+
+   if (buf[6] == 0 && buf[7] == 8)
+      printf("[CDROM] Current Profile: CD-ROM\n");
+   else
+      printf("[CDROM] Current Profile: %02X%02X\n", buf[6], buf[7]);
+
+   printf("[CDROM] Core Feature Descriptor: ");
+
+   for (i = 0; i < 12; i++)
+   {
+      printf("%02X ", buf[8 + i]);
+   }
+
+   printf("\n");
+
+   intf_std = buf[8 + 4] << 24 | buf[8 + 5] << 16 | buf[8 + 6] << 8 | buf[8 + 7];
+
+   switch (intf_std)
+   {
+      case 0:
+         intf_std_name = "Unspecified";
+         break;
+      case 1:
+         intf_std_name = "SCSI Family";
+         break;
+      case 2:
+         intf_std_name = "ATAPI";
+         break;
+      case 7:
+         intf_std_name = "Serial ATAPI";
+         break;
+      case 8:
+         intf_std_name = "USB";
+         break;
+      default:
+         break;
+   }
+
+   printf("[CDROM] Physical Interface Standard: %u (%s)\n", intf_std, intf_std_name);
+}
+
+int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *buf, size_t len)
+{
+   /* MMC Command: READ TOC/PMA/ATIP */
+   unsigned char cdb[] = {0x43, 0x2, 0x2, 0, 0, 0, 0x1, 0x9, 0x30, 0};
+#ifdef CDROM_DEBUG
+   unsigned short data_len = 0;
+   unsigned char first_session = 0;
+   unsigned char last_session = 0;
+   int i;
+#endif
+   int rv;
+
+   if (!buf)
+      return 1;
+
+   rv = cdrom_send_command(stream, DIRECTION_IN, buf, len, cdb, sizeof(cdb), 0);
+
+   if (rv)
+     return 1;
+
+#ifdef CDROM_DEBUG
+   data_len = buf[0] << 8 | buf[1];
+   first_session = buf[2];
+   last_session = buf[3];
+
+   printf("[CDROM] Data Length: %d\n", data_len);
+   printf("[CDROM] First Session: %d\n", first_session);
+   printf("[CDROM] Last Session: %d\n", last_session);
+
+   for (i = 0; i < (data_len - 2) / 11; i++)
+   {
+      unsigned char session_num = buf[4 + (i * 11) + 0];
+      unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
+      /*unsigned char control = buf[4 + (i * 11) + 1] & 0xF;*/
+      unsigned char tno = buf[4 + (i * 11) + 2];
+      unsigned char point = buf[4 + (i * 11) + 3];
+      unsigned char pmin = buf[4 + (i * 11) + 8];
+      unsigned char psec = buf[4 + (i * 11) + 9];
+      unsigned char pframe = buf[4 + (i * 11) + 10];
+
+      /*printf("i %d control %d adr %d tno %d point %d: ", i, control, adr, tno, point);*/
+      /* why is control always 0? */
+
+      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)
+      {
+         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
+         printf("Track start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
+      }
+      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA0)
+      {
+         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
+         printf("First Track Number: %d ", pmin);
+         printf("Disc Type: %d ", psec);
+      }
+      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)
+      {
+         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
+         printf("Last Track Number: %d ", pmin);
+      }
+      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA2)
+      {
+         printf("[CDROM] - Session#: %d TNO %d POINT %d ", session_num, tno, point);
+         printf("Lead-out start time: (aMSF %02u:%02u:%02u) ", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);
+      }
+
+      printf("\n");
+   }
+
+   fflush(stdout);
+#endif
+   return 0;
+}
+
+static int cdrom_read_track_info(libretro_vfs_implementation_file *stream, unsigned char track, cdrom_toc_t *toc)
+{
+   /* MMC Command: READ TRACK INFORMATION */
+   unsigned char cdb[] = {0x52, 0x1, 0, 0, 0, 0, 0, 0x1, 0x80, 0};
+   unsigned char buf[384] = {0};
+   unsigned lba = 0;
+   unsigned track_size = 0;
+   int rv;
+   ssize_t pregap_lba_len;
+
+   cdb[5] = track;
+
+   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+
+   if (rv)
+     return 1;
+
+   memcpy(&lba, buf + 8, 4);
+   memcpy(&track_size, buf + 24, 4);
+
+   lba = swap_if_little32(lba);
+   track_size = swap_if_little32(track_size);
+
+   /* lba_start may be earlier than the MSF start times seen in read_subq */
+   toc->track[track - 1].lba_start = lba;
+   toc->track[track - 1].track_size = track_size;
+
+   pregap_lba_len = (toc->track[track - 1].audio ? 0 : (toc->track[track - 1].lba - toc->track[track - 1].lba_start));
+
+   toc->track[track - 1].track_bytes = (track_size - pregap_lba_len) * 2352;
+   toc->track[track - 1].mode = buf[6] & 0xF;
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] Track %d Info: ", track);
+   printf("Copy: %d ", (buf[5] & 0x10) > 0);
+   printf("Data Mode: %d ", toc->track[track - 1].mode);
+   printf("LBA Start: %d (%d) ", lba, toc->track[track - 1].lba);
+   printf("Track Size: %d\n", track_size);
+   fflush(stdout);
+#endif
+
+   return 0;
+}
+
+int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed)
+{
+   /* MMC Command: SET CD SPEED */
+   unsigned char cmd[] = {0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+   cmd[2] = (speed >> 24) & 0xFF;
+   cmd[3] = (speed >> 16) & 0xFF;
+   cmd[4] = (speed >> 8) & 0xFF;
+   cmd[5] = speed & 0xFF;
+
+   return cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cmd, sizeof(cmd), 0);
+}
+
+int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc)
+{
+   unsigned char buf[2352] = {0};
+   unsigned short data_len = 0;
+   size_t len = 0;
+   size_t pos = 0;
+   int rv = 0;
+   int i;
+
+   if (!out_buf || !out_len || !num_tracks || !toc)
+   {
+#ifdef CDROM_DEBUG
+      printf("[CDROM] Invalid buffer/length pointer for CDROM cue sheet\n");
+      fflush(stdout);
+#endif
+      return 1;
+   }
+
+   cdrom_set_read_speed(stream, 0xFFFFFFFF);
+
+   rv = cdrom_read_subq(stream, buf, sizeof(buf));
+
+   if (rv)
+      return rv;
+
+   data_len = buf[0] << 8 | buf[1];
+
+   for (i = 0; i < (data_len - 2) / 11; i++)
+   {
+      unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
+      unsigned char tno = buf[4 + (i * 11) + 2];
+      unsigned char point = buf[4 + (i * 11) + 3];
+      unsigned char pmin = buf[4 + (i * 11) + 8];
+
+      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)
+      {
+         *num_tracks = pmin;
+#ifdef CDROM_DEBUG
+         printf("[CDROM] Number of CDROM tracks: %d\n", *num_tracks);
+         fflush(stdout);
+#endif
+         break;
+      }
+   }
+
+   if (!*num_tracks || *num_tracks > 99)
+   {
+#ifdef CDROM_DEBUG
+      printf("[CDROM] Invalid number of CDROM tracks: %d\n", *num_tracks);
+      fflush(stdout);
+#endif
+      return 1;
+   }
+
+   len = CDROM_CUE_TRACK_BYTES * (*num_tracks);
+   toc->num_tracks = *num_tracks;
+   *out_buf = (char*)calloc(1, len);
+   *out_len = len;
+
+   for (i = 0; i < (data_len - 2) / 11; i++)
+   {
+      /*unsigned char session_num = buf[4 + (i * 11) + 0];*/
+      unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;
+      unsigned char control = buf[4 + (i * 11) + 1] & 0xF;
+      unsigned char tno = buf[4 + (i * 11) + 2];
+      unsigned char point = buf[4 + (i * 11) + 3];
+      /*unsigned char amin = buf[4 + (i * 11) + 4];
+      unsigned char asec = buf[4 + (i * 11) + 5];
+      unsigned char aframe = buf[4 + (i * 11) + 6];*/
+      unsigned char pmin = buf[4 + (i * 11) + 8];
+      unsigned char psec = buf[4 + (i * 11) + 9];
+      unsigned char pframe = buf[4 + (i * 11) + 10];
+      unsigned lba = cdrom_msf_to_lba(pmin, psec, pframe);
+
+      /*printf("i %d control %d adr %d tno %d point %d: amin %d asec %d aframe %d pmin %d psec %d pframe %d\n", i, control, adr, tno, point, amin, asec, aframe, pmin, psec, pframe);*/
+      /* why is control always 0? */
+
+      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)
+      {
+         bool audio = false;
+         const char *track_type = "MODE1/2352";
+
+         audio = (!(control & 0x4) && !(control & 0x5));
+
+#ifdef CDROM_DEBUG
+         printf("[CDROM] Track %02d CONTROL %01X ADR %01X AUDIO? %d\n", point, control, adr, audio);
+         fflush(stdout);
+#endif
+
+         toc->track[point - 1].track_num = point;
+         toc->track[point - 1].min = pmin;
+         toc->track[point - 1].sec = psec;
+         toc->track[point - 1].frame = pframe;
+         toc->track[point - 1].lba = lba;
+         toc->track[point - 1].audio = audio;
+
+         cdrom_read_track_info(stream, point, toc);
+
+         if (audio)
+            track_type = "AUDIO";
+         else if (toc->track[point - 1].mode == 1)
+            track_type = "MODE1/2352";
+         else if (toc->track[point - 1].mode == 2)
+            track_type = "MODE2/2352";
+
+#if defined(_WIN32) && !defined(_XBOX)
+         pos += snprintf(*out_buf + pos, len - pos, "FILE \"cdrom://%c:/drive-track%02d.bin\" BINARY\n", cdrom_drive, point);
+#else
+         pos += snprintf(*out_buf + pos, len - pos, "FILE \"cdrom://drive%c-track%02d.bin\" BINARY\n", cdrom_drive, point);
+#endif
+         pos += snprintf(*out_buf + pos, len - pos, "  TRACK %02d %s\n", point, track_type);
+
+         {
+            unsigned pregap_lba_len = toc->track[point - 1].lba - toc->track[point - 1].lba_start;
+
+            if (toc->track[point - 1].audio && pregap_lba_len > 0)
+            {
+               unsigned char min = 0;
+               unsigned char sec = 0;
+               unsigned char frame = 0;
+
+               cdrom_lba_to_msf(pregap_lba_len, &min, &sec, &frame);
+
+               pos += snprintf(*out_buf + pos, len - pos, "    INDEX 00 00:00:00\n");
+               pos += snprintf(*out_buf + pos, len - pos, "    INDEX 01 %02u:%02u:%02u\n", (unsigned)min, (unsigned)sec, (unsigned)frame);
+            }
+            else
+               pos += snprintf(*out_buf + pos, len - pos, "    INDEX 01 00:00:00\n");
+         }
+      }
+   }
+
+   return 0;
+}
+
+/* needs 32 bytes for full vendor, product and version */
+int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *model, int len, bool *is_cdrom)
+{
+   /* MMC Command: INQUIRY */
+   unsigned char cdb[] = {0x12, 0, 0, 0, 0xff, 0};
+   unsigned char buf[256] = {0};
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+   bool cdrom = false;
+
+   if (rv)
+      return 1;
+
+   if (model && len >= 32)
+   {
+      memset(model, 0, len);
+
+      /* vendor */
+      memcpy(model, buf + 8, 8);
+
+      model[8] = ' ';
+
+      /* product */
+      memcpy(model + 9, buf + 16, 16);
+
+      model[25] = ' ';
+
+      /* version */
+      memcpy(model + 26, buf + 32, 4);
+   }
+
+   cdrom = (buf[0] == 5);
+
+   if (is_cdrom && cdrom)
+      *is_cdrom = true;
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] Device Model: %s (is CD-ROM? %s)\n", model, (cdrom ? "yes" : "no"));
+#endif
+   return 0;
+}
+
+int cdrom_read(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip)
+{
+   /* MMC Command: READ CD MSF */
+   unsigned char cdb[] = {0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0xF8, 0, 0};
+   int rv;
+   double frames = ceil((len + skip) / 2352.0);
+   unsigned frame_end = cdrom_msf_to_lba(min, sec, frame) + frames;
+
+   cdb[3] = min;
+   cdb[4] = sec;
+   cdb[5] = frame;
+
+   if (frames <= 1)
+   {
+      cdrom_lba_to_msf(frame_end, &cdb[6], &cdb[7], &cdb[8]);
+#ifdef CDROM_DEBUG
+      printf("[CDROM] single-frame read: %d %d %d skip %" PRId64 "\n", cdb[3], cdb[4], cdb[5], skip);
+      fflush(stdout);
+#endif
+   }
+   else
+   {
+      cdrom_lba_to_msf(frame_end, &cdb[6], &cdb[7], &cdb[8]);
+
+#ifdef CDROM_DEBUG
+      printf("[CDROM] multi-frame read: %d sectors starting from %02d:%02d:%02d skip %" PRId64 "\n", (int)frames, cdb[3], cdb[4], cdb[5], skip);
+      fflush(stdout);
+#endif
+   }
+
+   /* regardless of the length specified here, a new buffer will be allocated and padded to a sector multiple inside cdrom_send_command */
+   rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), skip);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] read msf status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+   {
+      stream->cdrom.last_frame_valid = false;
+      return 1;
+   }
+
+   return 0;
+}
+
+int cdrom_stop(libretro_vfs_implementation_file *stream)
+{
+   /* MMC Command: START STOP UNIT */
+   unsigned char cdb[] = {0x1B, 0, 0, 0, 0x0, 0};
+   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] stop status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return 1;
+
+   return 0;
+}
+
+int cdrom_unlock(libretro_vfs_implementation_file *stream)
+{
+   /* MMC Command: PREVENT ALLOW MEDIUM REMOVAL */
+   unsigned char cdb[] = {0x1E, 0, 0, 0, 0x2, 0};
+   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] persistent prevent clear status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return 1;
+
+   cdb[4] = 0x0;
+
+   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] prevent clear status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return 1;
+
+   return 0;
+}
+
+int cdrom_open_tray(libretro_vfs_implementation_file *stream)
+{
+   /* MMC Command: START STOP UNIT */
+   unsigned char cdb[] = {0x1B, 0, 0, 0, 0x2, 0};
+   int rv;
+
+   cdrom_unlock(stream);
+   cdrom_stop(stream);
+
+   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] open tray status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return 1;
+
+   return 0;
+}
+
+int cdrom_close_tray(libretro_vfs_implementation_file *stream)
+{
+   /* MMC Command: START STOP UNIT */
+   unsigned char cdb[] = {0x1B, 0, 0, 0, 0x3, 0};
+   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] close tray status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return 1;
+
+   return 0;
+}
+
+struct string_list* cdrom_get_available_drives(void)
+{
+   struct string_list *list = string_list_new();
+#if defined(__linux__) && !defined(ANDROID)
+   struct string_list *dir_list = dir_list_new("/dev", NULL, false, false, false, false);
+   int i;
+   bool found = false;
+
+   if (!dir_list)
+      return list;
+
+   for (i = 0; i < (int)dir_list->size; i++)
+   {
+      if (string_starts_with_size(dir_list->elems[i].data, "/dev/sg",
+               STRLEN_CONST("/dev/sg")))
+      {
+         libretro_vfs_implementation_file *stream;
+         char drive_model[32]             = {0};
+         char drive_string[33]            = {0};
+         union string_list_elem_attr attr = {0};
+         int dev_index                    = 0;
+         RFILE *file                      = filestream_open(
+               dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
+         bool is_cdrom                    = false;
+
+         found = true;
+
+         if (!file)
+         {
+#ifdef CDROM_DEBUG
+            printf("[CDROM] Could not open %s, please check permissions.\n", dir_list->elems[i].data);
+            fflush(stdout);
+#endif
+            continue;
+         }
+
+         stream = filestream_get_vfs_handle(file);
+         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom);
+         filestream_close(file);
+
+         if (!is_cdrom)
+            continue;
+
+         sscanf(dir_list->elems[i].data + STRLEN_CONST("/dev/sg"),
+               "%d", &dev_index);
+
+         dev_index = '0' + dev_index;
+         attr.i    = dev_index;
+
+         if (!string_is_empty(drive_model))
+            strlcat(drive_string, drive_model, sizeof(drive_string));
+         else
+            strlcat(drive_string, "Unknown Drive", sizeof(drive_string));
+
+         string_list_append(list, drive_string, attr);
+      }
+   }
+
+   if (!found)
+   {
+      char *buf   = NULL;
+      int64_t len = 0;
+
+      if (filestream_read_file("/proc/modules", (void**)&buf, &len))
+      {
+#ifdef CDROM_DEBUG
+         bool found              = false;
+#endif
+         struct string_list mods = {0};
+
+         string_list_initialize(&mods);
+         
+         if (string_split_noalloc(&mods, buf, "\n"))
+         {
+            for (i = 0; i < (int)mods.size; i++)
+            {
+               if (strcasestr(mods.elems[i].data, "sg "))
+               {
+#ifdef CDROM_DEBUG
+                  found = true;
+#endif
+                  break;
+               }
+            }
+         }
+         string_list_deinitialize(&mods);
+         free(buf);
+
+#ifdef CDROM_DEBUG
+         if (found)
+         {
+            printf("[CDROM] No sg devices found but kernel module is loaded.\n");
+            fflush(stdout);
+         }
+         else
+         {
+            printf("[CDROM] No sg devices found and sg kernel module is not loaded.\n");
+            fflush(stdout);
+         }
+#endif
+      }
+#ifdef CDROM_DEBUG
+      else
+      {
+         printf("[CDROM] No sg devices found, could not check if sg kernel module is loaded.\n");
+         fflush(stdout);
+      }
+#endif
+   }
+
+   string_list_free(dir_list);
+#endif
+#if defined(_WIN32) && !defined(_XBOX)
+   DWORD drive_mask = GetLogicalDrives();
+   int i;
+
+   for (i = 0; i < (int)(sizeof(DWORD) * 8); i++)
+   {
+      char path[]       = {"a:\\"};
+      char cdrom_path[] = {"cdrom://a:/drive-track01.bin"};
+
+      path[0]          += i;
+      cdrom_path[8]    += i;
+
+      /* this drive letter doesn't exist */
+      if (!(drive_mask & (1 << i)))
+         continue;
+
+      if (GetDriveType(path) != DRIVE_CDROM)
+         continue;
+
+      {
+         libretro_vfs_implementation_file *stream;
+         bool is_cdrom                    = false;
+         char drive_model[32]             = {0};
+         char drive_string[33]            = {0};
+         union string_list_elem_attr attr = {0};
+         RFILE *file = filestream_open(cdrom_path, RETRO_VFS_FILE_ACCESS_READ, 0);
+         if (!file)
+            continue;
+
+         stream = filestream_get_vfs_handle(file);
+         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom);
+         filestream_close(file);
+
+         if (!is_cdrom)
+            continue;
+
+         attr.i = path[0];
+
+         if (!string_is_empty(drive_model))
+            strlcat(drive_string, drive_model, sizeof(drive_string));
+         else
+            strlcat(drive_string, "Unknown Drive", sizeof(drive_string));
+
+         string_list_append(list, drive_string, attr);
+      }
+   }
+#endif
+   return list;
+}
+
+bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream)
+{
+   /* MMC Command: TEST UNIT READY */
+   unsigned char cdb[] = {0x00, 0, 0, 0, 0, 0};
+   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] media inserted status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   /* Will also return false if the drive is simply not ready yet (tray open, disc spinning back up after tray closed etc).
+    * Command will not block or wait for media to become ready. */
+   if (rv)
+      return false;
+
+   return true;
+}
+
+bool cdrom_drive_has_media(const char drive)
+{
+   RFILE *file;
+   char cdrom_path_bin[256] = {0};
+
+   cdrom_device_fillpath(cdrom_path_bin, sizeof(cdrom_path_bin), drive, 1, false);
+
+   file = filestream_open(cdrom_path_bin, RETRO_VFS_FILE_ACCESS_READ, 0);
+
+   if (file)
+   {
+      libretro_vfs_implementation_file *stream = filestream_get_vfs_handle(file);
+      bool has_media = cdrom_is_media_inserted(stream);
+
+      filestream_close(file);
+
+      return has_media;
+   }
+
+   return false;
+}
+
+bool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled)
+{
+   int i;
+   /* MMC Command: MODE SENSE (10) and MODE SELECT (10) */
+   unsigned char cdb_sense_changeable[] = {0x5A, 0, 0x48, 0, 0, 0, 0, 0, 0x14, 0};
+   unsigned char cdb_sense[]            = {0x5A, 0, 0x8, 0, 0, 0, 0, 0, 0x14, 0};
+   unsigned char cdb_select[]           = {0x55, 0x10, 0, 0, 0, 0, 0, 0, 0x14, 0};
+   unsigned char buf[20]                = {0};
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf),
+         cdb_sense_changeable, sizeof(cdb_sense_changeable), 0);
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] mode sense changeable status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return false;
+
+   if (!(buf[10] & 0x1))
+   {
+      /* RCD (read cache disable) bit is not changeable */
+#ifdef CDROM_DEBUG
+      printf("[CDROM] RCD (read cache disable) bit is not changeable.\n");
+      fflush(stdout);
+#endif
+      return false;
+   }
+
+   memset(buf, 0, sizeof(buf));
+
+   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb_sense, sizeof(cdb_sense), 0);
+
+#ifdef CDROM_DEBUG
+   printf("mode sense status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return false;
+
+#ifdef CDROM_DEBUG
+   printf("Mode sense data for caching mode page: ");
+
+   for (i = 0; i < (int)sizeof(buf); i++)
+      printf("%02X ", buf[i]);
+
+   printf("\n");
+   fflush(stdout);
+#endif
+
+   /* "When transferred during execution of the MODE SELECT (10) command, Mode Data Length is reserved." */
+   for (i = 0; i < 8; i++)
+      buf[i] = 0;
+
+   if (enabled)
+      buf[10] &= ~1;
+   else
+      buf[10] |=  1;
+
+   rv = cdrom_send_command(stream, DIRECTION_OUT, buf, sizeof(buf), cdb_select, sizeof(cdb_select), 0);
+
+#ifdef CDROM_DEBUG
+   printf("mode select status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return false;
+
+   return true;
+}
+
+bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts)
+{
+   /* MMC Command: MODE SENSE (10) */
+   int rv;
+   unsigned char cdb[]   = {0x5A, 0, 0x1D, 0, 0, 0, 0, 0, 0x14, 0};
+   unsigned char buf[20] = {0};
+   unsigned short g1     = 0;
+   unsigned short g2     = 0;
+   unsigned short g3     = 0;
+
+   if (!timeouts)
+      return false;
+
+   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+
+#ifdef CDROM_DEBUG
+   printf("get timeouts status code %d\n", rv);
+   fflush(stdout);
+#endif
+
+   if (rv)
+      return false;
+
+   g1 = buf[14] << 8 | buf[15];
+   g2 = buf[16] << 8 | buf[17];
+   g3 = buf[18] << 8 | buf[19];
+
+#ifdef CDROM_DEBUG
+   {
+      int i;
+
+      printf("Mode sense data for timeout groups: ");
+
+      for (i = 0; i < (int)sizeof(buf); i++)
+         printf("%02X ", buf[i]);
+
+      printf("\n");
+
+      printf("Group 1 Timeout: %d\n", g1);
+      printf("Group 2 Timeout: %d\n", g2);
+      printf("Group 3 Timeout: %d\n", g3);
+
+      fflush(stdout);
+   }
+#endif
+
+   timeouts->g1_timeout = g1;
+   timeouts->g2_timeout = g2;
+   timeouts->g3_timeout = g3;
+
+   return true;
+}
+
+bool cdrom_has_atip(libretro_vfs_implementation_file *stream)
+{
+   /* MMC Command: READ TOC/PMA/ATIP */
+   unsigned char cdb[]     = {0x43, 0x2, 0x4, 0, 0, 0, 0, 0x9, 0x30, 0};
+   unsigned char buf[32]   = {0};
+   unsigned short atip_len = 0;
+   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);
+
+   if (rv)
+     return false;
+
+   atip_len = buf[0] << 8 | buf[1];
+
+#ifdef CDROM_DEBUG
+   printf("ATIP Length %d, Disc Type %d, Disc Sub-Type %d\n",
+         atip_len,
+         (buf[6]  >> 6) & 0x1,
+         ((buf[6] >> 5) & 0x1) << 2 | ((buf[6] >> 4) & 0x1) << 1 | ((buf[6] >> 3) & 0x1) << 0);
+#endif
+
+   if (atip_len < 5)
+      return false;
+
+   return true;
+}
+
+void cdrom_device_fillpath(char *path, size_t len, char drive, unsigned char track, bool is_cue)
+{
+   if (!path || len == 0)
+      return;
+   if (is_cue)
+   {
+#ifdef _WIN32
+      size_t pos = strlcpy(path, "cdrom://", len);
+      if (len > pos)
+         path[pos++] = drive;
+      pos = strlcat(path, ":/drive.cue", len);
+#else
+#ifdef __linux__
+      size_t pos = strlcpy(path, "cdrom://drive", len);
+      if (len > pos + 1)
+      {
+         path[pos++] = drive;
+         path[pos]   = '\0';
+      }
+      pos = strlcat(path, ".cue", len);
+#endif
+#endif
+   }
+   else
+   {
+#ifdef _WIN32
+      size_t pos = strlcpy(path, "cdrom://", len);
+      if (len > pos + 1)
+      {
+         path[pos++] = drive;
+         path[pos]   = '\0';
+      }
+      pos += snprintf(path + pos, len - pos, ":/drive-track%02d.bin", track);
+#else
+#ifdef __linux__
+      size_t pos = strlcpy(path, "cdrom://drive", len);
+      if (len > pos)
+         path[pos++] = drive;
+      pos += snprintf(path + pos, len - pos, "-track%02d.bin", track);
+#endif
+#endif
+   }
+}
diff --git a/deps/libretro-common/compat/compat_fnmatch.c b/deps/libretro-common/compat/compat_fnmatch.c
new file mode 100644 (file)
index 0000000..8e46ce8
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_fnmatch.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stddef.h>
+
+#include <compat/fnmatch.h>
+
+/* Implemnentation of fnmatch(3) so it can be
+ * distributed to non *nix platforms.
+ *
+ * No flags are implemented ATM.
+ * We don't use them. Add flags as needed. */
+
+int rl_fnmatch(const char *pattern, const char *string, int flags)
+{
+   int rv;
+   const char *c = NULL;
+   int charmatch = 0;
+
+   for (c = pattern; *c != '\0'; c++)
+   {
+      /* String ended before pattern */
+      if ((*c != '*') && (*string == '\0'))
+         return FNM_NOMATCH;
+
+      switch (*c)
+      {
+         /* Match any number of unknown chars */
+         case '*':
+            /* Find next node in the pattern
+             * ignoring multiple asterixes
+             */
+            do {
+               c++;
+               if (*c == '\0')
+                  return 0;
+            } while (*c == '*');
+
+            /* Match the remaining pattern
+             * ignoring more and more characters. */
+            do {
+               /* We reached the end of the string without a
+                * match. There is a way to optimize this by
+                * calculating the minimum chars needed to
+                * match the remaining pattern but I don't
+                * think it is worth the work ATM.
+                */
+               if (*string == '\0')
+                  return FNM_NOMATCH;
+
+               rv = rl_fnmatch(c, string, flags);
+               string++;
+            } while (rv != 0);
+
+            return 0;
+            /* Match char from list */
+         case '[':
+            charmatch = 0;
+            for (c++; *c != ']'; c++)
+            {
+               /* Bad format */
+               if (*c == '\0')
+                  return FNM_NOMATCH;
+
+               /* Match already found */
+               if (charmatch)
+                  continue;
+
+               if (*c == *string)
+                  charmatch = 1;
+            }
+
+            /* No match in list */
+            if (!charmatch)
+               return FNM_NOMATCH;
+
+            string++;
+            break;
+            /* Has any character */
+         case '?':
+            string++;
+            break;
+            /* Match following character verbatim */
+         case '\\':
+            c++;
+            /* Dangling escape at end of pattern.
+             * FIXME: Was c == '\0' (makes no sense).
+             * Not sure if c == NULL or *c == '\0'
+             * is intended. Assuming *c due to c++ right before. */
+            if (*c == '\0')
+               return FNM_NOMATCH;
+         default:
+            if (*c != *string)
+               return FNM_NOMATCH;
+            string++;
+      }
+   }
+
+   /* End of string and end of pattend */
+   if (*string == '\0')
+      return 0;
+   return FNM_NOMATCH;
+}
diff --git a/deps/libretro-common/compat/compat_getopt.c b/deps/libretro-common/compat/compat_getopt.c
new file mode 100644 (file)
index 0000000..2d16522
--- /dev/null
@@ -0,0 +1,230 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_getopt.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <ctype.h>
+
+#include <string.h>
+#include <boolean.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <retro_miscellaneous.h>
+
+#include <compat/getopt.h>
+#include <compat/strl.h>
+#include <compat/strcasestr.h>
+#include <compat/posix_string.h>
+
+char *optarg;
+int optind, opterr, optopt;
+
+static bool is_short_option(const char *str)
+{
+   return str[0] == '-' && str[1] != '-';
+}
+
+static bool is_long_option(const char *str)
+{
+   return str[0] == '-' && str[1] == '-';
+}
+
+static int find_short_index(char * const *argv)
+{
+   int idx;
+   for (idx = 0; argv[idx]; idx++)
+   {
+      if (is_short_option(argv[idx]))
+         return idx;
+   }
+
+   return -1;
+}
+
+static int find_long_index(char * const *argv)
+{
+   int idx;
+   for (idx = 0; argv[idx]; idx++)
+   {
+      if (is_long_option(argv[idx]))
+         return idx;
+   }
+
+   return -1;
+}
+
+static int parse_short(const char *optstring, char * const *argv)
+{
+   bool extra_opt, takes_arg, embedded_arg;
+   const char *opt = NULL;
+   char        arg = argv[0][1];
+
+   if (arg == ':')
+      return '?';
+
+   opt = strchr(optstring, arg);
+   if (!opt)
+      return '?';
+
+   extra_opt = argv[0][2];
+   takes_arg = opt[1] == ':';
+
+   /* If we take an argument, and we see additional characters,
+    * this is in fact the argument (i.e. -cfoo is same as -c foo). */
+   embedded_arg = extra_opt && takes_arg;
+
+   if (takes_arg)
+   {
+      if (embedded_arg)
+      {
+         optarg = argv[0] + 2;
+         optind++;
+      }
+      else
+      {
+         optarg = argv[1];
+         optind += 2;
+      }
+
+      return optarg ? opt[0] : '?';
+   }
+
+   if (embedded_arg)
+   {
+      /* If we see additional characters,
+       * and they don't take arguments, this
+       * means we have multiple flags in one. */
+      memmove(&argv[0][1], &argv[0][2], strlen(&argv[0][2]) + 1);
+      return opt[0];
+   }
+
+   optind++;
+   return opt[0];
+}
+
+static int parse_long(const struct option *longopts, char * const *argv)
+{
+   size_t indice;
+   char *save  = NULL;
+   char *argv0 = strdup(&argv[0][2]);
+   char *token = strtok_r(argv0, "=", &save);
+   const struct option *opt = NULL;
+
+   for (indice = 0; longopts[indice].name; indice++)
+   {
+      if (token && !strcmp(longopts[indice].name, token))
+      {
+         opt = &longopts[indice];
+         break;
+      }
+   }
+
+   free(argv0);
+   argv0 = NULL;
+
+   if (!opt)
+      return '?';
+
+   /* Handle args with '=' instead of space */
+   if (opt->has_arg)
+   {
+      char *special_arg = strchr(argv[0], '=');
+      if (special_arg)
+      {
+         optarg = ++special_arg;
+         optind++;
+         return opt->val;
+      }
+   }
+
+   /* getopt_long has an "optional" arg, but we don't bother with that. */
+   if (opt->has_arg && !argv[1])
+      return '?';
+
+   if (opt->has_arg)
+   {
+      optarg = argv[1];
+      optind += 2;
+   }
+   else
+      optind++;
+
+   if (opt->flag)
+   {
+      *opt->flag = opt->val;
+      return 0;
+   }
+
+   return opt->val;
+}
+
+static void shuffle_block(char **begin, char **last, char **end)
+{
+   ptrdiff_t    len = last - begin;
+   const char **tmp = (const char**)calloc(len, sizeof(const char*));
+
+   memcpy((void*)tmp, begin, len * sizeof(const char*));
+   memmove(begin, last, (end - last) * sizeof(const char*));
+   memcpy(end - len, tmp, len * sizeof(const char*));
+
+   free((void*)tmp);
+}
+
+int getopt_long(int argc, char *argv[],
+      const char *optstring, const struct option *longopts, int *longindex)
+{
+   int short_index, long_index;
+
+   if (optind == 0)
+      optind = 1;
+
+   if (argc < 2)
+      return -1;
+
+   short_index = find_short_index(&argv[optind]);
+   long_index  = find_long_index(&argv[optind]);
+
+   /* We're done here. */
+   if (short_index == -1 && long_index == -1)
+      return -1;
+
+   /* Reorder argv so that non-options come last.
+    * Non-POSIXy, but that's what getopt does by default. */
+   if ((short_index > 0) && ((short_index < long_index) || (long_index == -1)))
+   {
+      shuffle_block(&argv[optind], &argv[optind + short_index], &argv[argc]);
+      short_index = 0;
+   }
+   else if ((long_index > 0) && ((long_index < short_index)
+            || (short_index == -1)))
+   {
+      shuffle_block(&argv[optind], &argv[optind + long_index], &argv[argc]);
+      long_index = 0;
+   }
+
+   if (short_index == 0)
+      return parse_short(optstring, &argv[optind]);
+   if (long_index == 0)
+      return parse_long(longopts, &argv[optind]);
+
+   return '?';
+}
diff --git a/deps/libretro-common/compat/compat_ifaddrs.c b/deps/libretro-common/compat/compat_ifaddrs.c
new file mode 100644 (file)
index 0000000..4a270b6
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+Copyright (c) 2013, Kenneth MacKay
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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 HOLDER 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 <compat/ifaddrs.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+typedef struct NetlinkList
+{
+    struct NetlinkList *m_next;
+    struct nlmsghdr *m_data;
+    unsigned int m_size;
+} NetlinkList;
+
+static int netlink_socket(void)
+{
+   struct sockaddr_nl l_addr;
+   int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+   if (l_socket < 0)
+      return -1;
+
+   memset(&l_addr, 0, sizeof(l_addr));
+   l_addr.nl_family = AF_NETLINK;
+
+   if (bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
+   {
+      close(l_socket);
+      return -1;
+   }
+
+   return l_socket;
+}
+
+static int netlink_send(int p_socket, int p_request)
+{
+   struct
+   {
+      struct nlmsghdr m_hdr;
+      struct rtgenmsg m_msg;
+   } l_data;
+   struct sockaddr_nl l_addr;
+
+   memset(&l_data, 0, sizeof(l_data));
+
+   l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+   l_data.m_hdr.nlmsg_type = p_request;
+   l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+   l_data.m_hdr.nlmsg_pid = 0;
+   l_data.m_hdr.nlmsg_seq = p_socket;
+   l_data.m_msg.rtgen_family = AF_UNSPEC;
+
+   memset(&l_addr, 0, sizeof(l_addr));
+   l_addr.nl_family = AF_NETLINK;
+   return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
+}
+
+static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
+{
+   struct msghdr l_msg;
+   struct iovec l_iov = { p_buffer, p_len };
+   struct sockaddr_nl l_addr;
+
+   for (;;)
+   {
+      int l_result;
+
+      l_msg.msg_name       = (void *)&l_addr;
+      l_msg.msg_namelen    = sizeof(l_addr);
+      l_msg.msg_iov        = &l_iov;
+      l_msg.msg_iovlen     = 1;
+      l_msg.msg_control    = NULL;
+      l_msg.msg_controllen = 0;
+      l_msg.msg_flags      = 0;
+
+      l_result             = recvmsg(p_socket, &l_msg, 0);
+
+      if (l_result < 0)
+      {
+         if (errno == EINTR)
+            continue;
+         return -2;
+      }
+
+      if (l_msg.msg_flags & MSG_TRUNC) /* buffer too small */
+         return -1;
+      return l_result;
+   }
+}
+
+static struct nlmsghdr *getNetlinkResponse(int p_socket,
+      int *p_size, int *p_done)
+{
+   size_t l_size  = 4096;
+   void *l_buffer = NULL;
+
+   for (;;)
+   {
+      int l_read;
+
+      free(l_buffer);
+      l_buffer = malloc(l_size);
+      if (!l_buffer)
+         return NULL;
+
+      l_read  = netlink_recv(p_socket, l_buffer, l_size);
+      *p_size = l_read;
+
+      if (l_read == -2)
+      {
+         free(l_buffer);
+         return NULL;
+      }
+
+      if (l_read >= 0)
+      {
+         pid_t l_pid = getpid();
+         struct nlmsghdr *l_hdr;
+
+         for (l_hdr = (struct nlmsghdr *)l_buffer;
+               NLMSG_OK(l_hdr, (unsigned int)l_read);
+               l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
+         {
+            if (  (pid_t)l_hdr->nlmsg_pid != l_pid || 
+                  (int)l_hdr->nlmsg_seq   != p_socket)
+               continue;
+
+            if (l_hdr->nlmsg_type == NLMSG_DONE)
+            {
+               *p_done = 1;
+               break;
+            }
+
+            if (l_hdr->nlmsg_type == NLMSG_ERROR)
+            {
+               free(l_buffer);
+               return NULL;
+            }
+         }
+         return l_buffer;
+      }
+
+      l_size *= 2;
+   }
+}
+
+static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
+{
+   NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList));
+   if (!l_item)
+      return NULL;
+
+   l_item->m_next = NULL;
+   l_item->m_data = p_data;
+   l_item->m_size = p_size;
+   return l_item;
+}
+
+static void freeResultList(NetlinkList *p_list)
+{
+   NetlinkList *l_cur;
+
+   while (p_list)
+   {
+      l_cur = p_list;
+      p_list = p_list->m_next;
+      free(l_cur->m_data);
+      free(l_cur);
+   }
+}
+
+static NetlinkList *getResultList(int p_socket, int p_request)
+{
+   int l_size;
+   NetlinkList *l_list = NULL;
+   NetlinkList *l_end  = NULL;
+   int l_done          = 0;
+
+   if (netlink_send(p_socket, p_request) < 0)
+      return NULL;
+
+   while (!l_done)
+   {
+      NetlinkList *l_item    = NULL;
+      struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+      if (!l_hdr)
+         goto error;
+
+      l_item = newListItem(l_hdr, l_size);
+      if (!l_item)
+         goto error;
+
+      if (!l_list)
+         l_list        = l_item;
+      else
+         l_end->m_next = l_item;
+      l_end            = l_item;
+   }
+
+   return l_list;
+
+error:
+   freeResultList(l_list);
+   return NULL;
+}
+
+static size_t maxSize(size_t a, size_t b)
+{
+   return (a > b ? a : b);
+}
+
+static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
+{
+   switch(p_family)
+   {
+      case AF_INET:
+         return sizeof(struct sockaddr_in);
+      case AF_INET6:
+         return sizeof(struct sockaddr_in6);
+      case AF_PACKET:
+         return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
+      default:
+         break;
+   }
+
+   return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
+}
+
+static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
+{
+   switch(p_family)
+   {
+      case AF_INET:
+         memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
+         break;
+      case AF_INET6:
+         memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
+         break;
+      case AF_PACKET:
+         memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
+         ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
+         break;
+      default:
+         memcpy(p_dest->sa_data, p_data, p_size);
+         break;
+   }
+   p_dest->sa_family = p_family;
+}
+
+static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
+{
+   if (!*p_resultList)
+      *p_resultList = p_entry;
+   else
+   {
+      struct ifaddrs *l_cur = *p_resultList;
+      while (l_cur->ifa_next)
+         l_cur = l_cur->ifa_next;
+      l_cur->ifa_next = p_entry;
+   }
+}
+
+static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
+{
+   struct ifaddrs *l_entry  = NULL;
+   struct rtattr *l_rta     = NULL;
+   struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
+   size_t l_nameSize        = 0;
+   size_t l_addrSize        = 0;
+   size_t l_dataSize        = 0;
+   size_t l_rtaSize         = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+
+   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
+         l_rta = RTA_NEXT(l_rta, l_rtaSize))
+   {
+      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+      switch(l_rta->rta_type)
+      {
+         case IFLA_ADDRESS:
+         case IFLA_BROADCAST:
+            l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
+            break;
+         case IFLA_IFNAME:
+            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+            break;
+         case IFLA_STATS:
+            l_dataSize += NLMSG_ALIGN(l_rtaSize);
+            break;
+         default:
+            break;
+      }
+   }
+
+   l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
+   if (!l_entry)
+      return -1;
+
+   memset(l_entry, 0, sizeof(struct ifaddrs));
+   l_entry->ifa_name = "";
+
+   char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
+   char *l_name = l_index + sizeof(int);
+   char *l_addr = l_name + l_nameSize;
+   char *l_data = l_addr + l_addrSize;
+
+   /* save the interface index so we can look 
+    * it up when handling the addresses. */
+   memcpy(l_index, &l_info->ifi_index, sizeof(int));
+
+   l_entry->ifa_flags = l_info->ifi_flags;
+
+   l_rtaSize          = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+
+   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
+         l_rta = RTA_NEXT(l_rta, l_rtaSize))
+   {
+      void      *l_rtaData = RTA_DATA(l_rta);
+      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+
+      switch(l_rta->rta_type)
+      {
+         case IFLA_ADDRESS:
+         case IFLA_BROADCAST:
+            {
+               size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
+               makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+               ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
+               ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
+               if (l_rta->rta_type == IFLA_ADDRESS)
+                  l_entry->ifa_addr      = (struct sockaddr *)l_addr;
+               else
+                  l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+               l_addr += NLMSG_ALIGN(l_addrLen);
+               break;
+            }
+         case IFLA_IFNAME:
+            strncpy(l_name, l_rtaData, l_rtaDataSize);
+            l_name[l_rtaDataSize] = '\0';
+            l_entry->ifa_name = l_name;
+            break;
+         case IFLA_STATS:
+            memcpy(l_data, l_rtaData, l_rtaDataSize);
+            l_entry->ifa_data = l_data;
+            break;
+         default:
+            break;
+      }
+   }
+
+   addToEnd(p_resultList, l_entry);
+   return 0;
+}
+
+static struct ifaddrs *findInterface(int p_index,
+      struct ifaddrs **p_links, int p_numLinks)
+{
+   int l_num             = 0;
+   struct ifaddrs *l_cur = *p_links;
+
+   while (l_cur && l_num < p_numLinks)
+   {
+      int l_index;
+      char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
+
+      memcpy(&l_index, l_indexPtr, sizeof(int));
+      if (l_index == p_index)
+         return l_cur;
+
+      l_cur = l_cur->ifa_next;
+      ++l_num;
+   }
+   return NULL;
+}
+
+static int interpretAddr(struct nlmsghdr *p_hdr,
+      struct ifaddrs **p_resultList, int p_numLinks)
+{
+   struct rtattr *l_rta;
+   size_t l_rtaSize;
+   size_t l_nameSize           = 0;
+   size_t l_addrSize           = 0;
+   int l_addedNetmask          = 0;
+   struct ifaddrmsg *l_info    = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
+   struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
+
+   if (l_info->ifa_family == AF_PACKET)
+      return 0;
+
+   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+
+   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
+         l_rta = RTA_NEXT(l_rta, l_rtaSize))
+   {
+      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+
+      switch(l_rta->rta_type)
+      {
+         case IFA_ADDRESS:
+         case IFA_LOCAL:
+            if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
+            {
+               /* make room for netmask */
+               l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+               l_addedNetmask = 1;
+            }
+         case IFA_BROADCAST:
+            l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+            break;
+         case IFA_LABEL:
+            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+            break;
+         default:
+            break;
+      }
+   }
+
+   struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
+   if (!l_entry)
+      return -1;
+
+   memset(l_entry, 0, sizeof(struct ifaddrs));
+   l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
+
+   char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
+   char *l_addr = l_name + l_nameSize;
+
+   l_entry->ifa_flags = l_info->ifa_flags;
+   if (l_interface)
+      l_entry->ifa_flags |= l_interface->ifa_flags;
+
+   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
+         l_rta = RTA_NEXT(l_rta, l_rtaSize))
+   {
+      void *l_rtaData = RTA_DATA(l_rta);
+      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+      switch(l_rta->rta_type)
+      {
+         case IFA_ADDRESS:
+         case IFA_BROADCAST:
+         case IFA_LOCAL:
+            {
+               size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
+               makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+               if (l_info->ifa_family == AF_INET6)
+               {
+                  if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
+                     ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
+               }
+
+               if (l_rta->rta_type == IFA_ADDRESS)
+               {
+                  /* apparently in a point-to-point network IFA_ADDRESS
+                   * contains the dest address and IFA_LOCAL contains the local address */
+                  if (l_entry->ifa_addr)
+                     l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
+                  else
+                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
+               }
+               else if (l_rta->rta_type == IFA_LOCAL)
+               {
+                  if (l_entry->ifa_addr)
+                     l_entry->ifa_dstaddr = l_entry->ifa_addr;
+                  l_entry->ifa_addr = (struct sockaddr *)l_addr;
+               }
+               else
+                  l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+               l_addr += NLMSG_ALIGN(l_addrLen);
+               break;
+            }
+         case IFA_LABEL:
+            strncpy(l_name, l_rtaData, l_rtaDataSize);
+            l_name[l_rtaDataSize] = '\0';
+            l_entry->ifa_name = l_name;
+            break;
+         default:
+            break;
+      }
+   }
+
+   if (l_entry->ifa_addr &&
+         (   l_entry->ifa_addr->sa_family == AF_INET
+          || l_entry->ifa_addr->sa_family == AF_INET6))
+   {
+      unsigned i;
+      char l_mask[16];
+      unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET
+            ? 32 : 128);
+      unsigned l_prefix    = (l_info->ifa_prefixlen > l_maxPrefix
+            ? l_maxPrefix : l_info->ifa_prefixlen);
+
+      l_mask[0] = '\0';
+
+      for (i=0; i<(l_prefix/8); ++i)
+         l_mask[i] = 0xff;
+      if (l_prefix % 8)
+         l_mask[i] = 0xff << (8 - (l_prefix % 8));
+
+      makeSockaddr(l_entry->ifa_addr->sa_family,
+            (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
+      l_entry->ifa_netmask = (struct sockaddr *)l_addr;
+   }
+
+   addToEnd(p_resultList, l_entry);
+   return 0;
+}
+
+static int interpretLinks(int p_socket, NetlinkList *p_netlinkList,
+      struct ifaddrs **p_resultList)
+{
+   int l_numLinks = 0;
+   pid_t l_pid    = getpid();
+
+   for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+   {
+      struct nlmsghdr *l_hdr = NULL;
+      unsigned int l_nlsize  = p_netlinkList->m_size;
+
+      for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
+            l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+      {
+         if (  (pid_t)l_hdr->nlmsg_pid != l_pid || 
+               (int)l_hdr->nlmsg_seq   != p_socket)
+            continue;
+
+         if (l_hdr->nlmsg_type == NLMSG_DONE)
+            break;
+
+         if (l_hdr->nlmsg_type == RTM_NEWLINK)
+         {
+            if (interpretLink(l_hdr, p_resultList) == -1)
+               return -1;
+            ++l_numLinks;
+         }
+      }
+   }
+   return l_numLinks;
+}
+
+static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
+      struct ifaddrs **p_resultList, int p_numLinks)
+{
+   pid_t l_pid = getpid();
+   for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+   {
+      struct nlmsghdr *l_hdr = NULL;
+      unsigned int l_nlsize  = p_netlinkList->m_size;
+
+      for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
+            l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+      {
+         if (     (pid_t)l_hdr->nlmsg_pid != l_pid 
+               || (int)l_hdr->nlmsg_seq   != p_socket)
+            continue;
+
+         if (l_hdr->nlmsg_type == NLMSG_DONE)
+            break;
+
+         if (l_hdr->nlmsg_type == RTM_NEWADDR)
+         {
+            if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
+               return -1;
+         }
+      }
+   }
+   return 0;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+   NetlinkList *l_linkResults;
+   NetlinkList *l_addrResults;
+   int l_numLinks;
+   int l_socket   = 0;
+   int l_result   = 0;
+   if (!ifap)
+      return -1;
+
+   *ifap    = NULL;
+
+   l_socket = netlink_socket();
+
+   if (l_socket < 0)
+      return -1;
+
+   l_linkResults = getResultList(l_socket, RTM_GETLINK);
+   if (!l_linkResults)
+   {
+      close(l_socket);
+      return -1;
+   }
+
+   l_addrResults = getResultList(l_socket, RTM_GETADDR);
+   if (!l_addrResults)
+   {
+      close(l_socket);
+      freeResultList(l_linkResults);
+      return -1;
+   }
+
+   l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
+
+   if (  l_numLinks == -1 || 
+         interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
+      l_result = -1;
+
+   freeResultList(l_linkResults);
+   freeResultList(l_addrResults);
+   close(l_socket);
+   return l_result;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+   struct ifaddrs *l_cur = NULL;
+
+   while (ifa)
+   {
+      l_cur = ifa;
+      ifa   = ifa->ifa_next;
+      free(l_cur);
+   }
+}
diff --git a/deps/libretro-common/compat/compat_posix_string.c b/deps/libretro-common/compat/compat_posix_string.c
new file mode 100644 (file)
index 0000000..6a2f07e
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_posix_string.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <ctype.h>
+
+#include <compat/posix_string.h>
+
+#ifdef _WIN32
+
+#undef strcasecmp
+#undef strdup
+#undef isblank
+#undef strtok_r
+#include <ctype.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <compat/strl.h>
+
+#include <string.h>
+
+int retro_strcasecmp__(const char *a, const char *b)
+{
+   while (*a && *b)
+   {
+      int a_ = tolower(*a);
+      int b_ = tolower(*b);
+
+      if (a_ != b_)
+         return a_ - b_;
+
+      a++;
+      b++;
+   }
+
+   return tolower(*a) - tolower(*b);
+}
+
+char *retro_strdup__(const char *orig)
+{
+   size_t len = strlen(orig) + 1;
+   char *ret  = (char*)malloc(len);
+   if (!ret)
+      return NULL;
+
+   strlcpy(ret, orig, len);
+   return ret;
+}
+
+int retro_isblank__(int c)
+{
+   return (c == ' ') || (c == '\t');
+}
+
+char *retro_strtok_r__(char *str, const char *delim, char **saveptr)
+{
+   char *first = NULL;
+   if (!saveptr || !delim)
+      return NULL;
+
+   if (str)
+      *saveptr = str;
+
+   do
+   {
+      char *ptr = NULL;
+      first = *saveptr;
+      while (*first && strchr(delim, *first))
+         *first++ = '\0';
+
+      if (*first == '\0')
+         return NULL;
+
+      ptr = first + 1;
+
+      while (*ptr && !strchr(delim, *ptr))
+         ptr++;
+
+      *saveptr = ptr + (*ptr ? 1 : 0);
+      *ptr     = '\0';
+   } while (strlen(first) == 0);
+
+   return first;
+}
+
+#endif
diff --git a/deps/libretro-common/compat/compat_snprintf.c b/deps/libretro-common/compat/compat_snprintf.c
new file mode 100644 (file)
index 0000000..d7320cc
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_snprintf.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
+#ifdef _MSC_VER
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#if _MSC_VER < 1800
+#define va_copy(dst, src) ((dst) = (src))
+#endif
+
+#if _MSC_VER < 1300
+#define _vscprintf c89_vscprintf_retro__
+
+static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
+{
+   int retval;
+   va_list argcopy;
+   va_copy(argcopy, pargs);
+   retval = vsnprintf(NULL, 0, fmt, argcopy);
+   va_end(argcopy);
+   return retval;
+}
+#endif
+
+/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
+
+int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
+{
+   int count = -1;
+
+   if (len != 0)
+   {
+#if (_MSC_VER <= 1310)
+      count = _vsnprintf(s, len - 1, fmt, ap);
+#else
+      count = _vsnprintf_s(s, len, len - 1, fmt, ap);
+#endif
+   }
+
+   if (count == -1)
+       count = _vscprintf(fmt, ap);
+
+   /* there was no room for a NULL, so truncate the last character */
+   if (count == len && len)
+      s[len - 1] = '\0';
+
+   return count;
+}
+
+int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
+{
+   int count;
+   va_list ap;
+
+   va_start(ap, fmt);
+   count = c99_vsnprintf_retro__(s, len, fmt, ap);
+   va_end(ap);
+
+   return count;
+}
+#endif
diff --git a/deps/libretro-common/compat/compat_strcasestr.c b/deps/libretro-common/compat/compat_strcasestr.c
new file mode 100644 (file)
index 0000000..4129dab
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_strcasestr.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <ctype.h>
+
+#include <compat/strcasestr.h>
+
+/* Pretty much strncasecmp. */
+static int casencmp(const char *a, const char *b, size_t n)
+{
+   size_t i;
+
+   for (i = 0; i < n; i++)
+   {
+      int a_lower = tolower(a[i]);
+      int b_lower = tolower(b[i]);
+      if (a_lower != b_lower)
+         return a_lower - b_lower;
+   }
+
+   return 0;
+}
+
+char *strcasestr_retro__(const char *haystack, const char *needle)
+{
+   size_t i, search_off;
+   size_t hay_len    = strlen(haystack);
+   size_t needle_len = strlen(needle);
+
+   if (needle_len > hay_len)
+      return NULL;
+
+   search_off = hay_len - needle_len;
+   for (i = 0; i <= search_off; i++)
+      if (!casencmp(haystack + i, needle, needle_len))
+         return (char*)haystack + i;
+
+   return NULL;
+}
diff --git a/deps/libretro-common/compat/compat_strl.c b/deps/libretro-common/compat/compat_strl.c
new file mode 100644 (file)
index 0000000..3a6392c
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_strl.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <ctype.h>
+
+#include <compat/strl.h>
+
+/* Implementation of strlcpy()/strlcat() based on OpenBSD. */
+
+#ifndef __MACH__
+
+size_t strlcpy(char *dest, const char *source, size_t size)
+{
+   size_t src_size = 0;
+   size_t        n = size;
+
+   if (n)
+      while (--n && (*dest++ = *source++)) src_size++;
+
+   if (!n)
+   {
+      if (size) *dest = '\0';
+      while (*source++) src_size++;
+   }
+
+   return src_size;
+}
+
+size_t strlcat(char *dest, const char *source, size_t size)
+{
+   size_t len = strlen(dest);
+
+   dest += len;
+
+   if (len > size)
+      size = 0;
+   else
+      size -= len;
+
+   return len + strlcpy(dest, source, size);
+}
+#endif
diff --git a/deps/libretro-common/compat/compat_strldup.c b/deps/libretro-common/compat/compat_strldup.c
new file mode 100644 (file)
index 0000000..3a594eb
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_strl.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <ctype.h>
+
+#include <compat/strl.h>
+
+char *strldup(const char *s, size_t n)
+{
+   char *dst = (char*)malloc(sizeof(char) * (n + 1));
+   strlcpy(dst, s, n);
+   return dst;
+}
diff --git a/deps/libretro-common/compat/compat_vscprintf.c b/deps/libretro-common/compat/compat_vscprintf.c
new file mode 100644 (file)
index 0000000..50e9e8d
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_snprintf.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
+#ifdef _MSC_VER
+
+#include <retro_common.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#define va_copy(dst, src) ((dst) = (src))
+#endif
+
+int c89_vscprintf_retro__(const char *format, va_list pargs)
+{
+   int retval;
+   va_list argcopy;
+   va_copy(argcopy, pargs);
+   retval = vsnprintf(NULL, 0, format, argcopy);
+   va_end(argcopy);
+   return retval;
+}
+#endif
diff --git a/deps/libretro-common/compat/fopen_utf8.c b/deps/libretro-common/compat/fopen_utf8.c
new file mode 100644 (file)
index 0000000..384657b
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fopen_utf8.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <compat/fopen_utf8.h>
+#include <encodings/utf.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+#endif
+
+#ifdef _WIN32
+#undef fopen
+
+void *fopen_utf8(const char * filename, const char * mode)
+{
+#if defined(LEGACY_WIN32)
+   char * filename_local = utf8_to_local_string_alloc(filename);
+   if (filename_local)
+   {
+      FILE *ret          = fopen(filename_local, mode);
+      free(filename_local);
+      return ret;
+   }
+#else
+   wchar_t * filename_w  = utf8_to_utf16_string_alloc(filename);
+   if (filename_w)
+   {
+      FILE    *ret       = NULL;
+      wchar_t *mode_w    = utf8_to_utf16_string_alloc(mode);
+      if (mode_w)
+      {
+         ret             = _wfopen(filename_w, mode_w);
+         free(mode_w);
+      }
+      free(filename_w);
+      return ret;
+   }
+#endif
+   return NULL;
+}
+#endif
diff --git a/deps/libretro-common/crt/include/string.h b/deps/libretro-common/crt/include/string.h
new file mode 100644 (file)
index 0000000..25fbfc4
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __LIBRETRO_SDK_CRT_STRING_H_
+#define __LIBRETRO_SDK_CRT_STRING_H_
+
+#include <stdio.h>
+
+void *memcpy(void *dst, const void *src, size_t len);
+
+void *memset(void *b, int c, size_t len);
+
+#endif
diff --git a/deps/libretro-common/crt/string.c b/deps/libretro-common/crt/string.c
new file mode 100644 (file)
index 0000000..4114de1
--- /dev/null
@@ -0,0 +1,34 @@
+#ifdef _MSC_VER
+#include <cruntime.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+void *memset(void *dst, int val, size_t count)
+{
+   void *start = dst;
+
+#if defined(_M_IA64) || defined (_M_AMD64) || defined(_M_ALPHA) || defined (_M_PPC)
+   extern void RtlFillMemory(void *, size_t count, char);
+
+   RtlFillMemory(dst, count, (char)val);
+#else
+   while (count--)
+   {
+      *(char*)dst = (char)val;
+      dst = (char*)dst + 1;
+   }
+#endif
+
+   return start;
+}
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+   size_t i;
+
+   for (i = 0; i < len; i++)
+      ((unsigned char *)dst)[i] = ((unsigned char *)src)[i];
+
+   return dst;
+}
diff --git a/deps/libretro-common/dynamic/dylib.c b/deps/libretro-common/dynamic/dylib.c
new file mode 100644 (file)
index 0000000..248c612
--- /dev/null
@@ -0,0 +1,225 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (dylib.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <string.h>
+#include <stdio.h>
+#include <dynamic/dylib.h>
+#include <encodings/utf.h>
+
+#if defined(ORBIS)
+#include <orbis/libkernel.h>
+#endif
+
+#ifdef NEED_DYNAMIC
+
+#ifdef _WIN32
+#include <compat/posix_string.h>
+#include <windows.h>
+#else
+#if !defined(ORBIS)
+#include <dlfcn.h>
+#endif
+#endif
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+
+#endif
+
+#ifdef _WIN32
+static char last_dyn_error[512];
+
+static void set_dl_error(void)
+{
+   DWORD err = GetLastError();
+
+   if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
+            FORMAT_MESSAGE_FROM_SYSTEM,
+            NULL,
+            err,
+            MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
+            last_dyn_error,
+            sizeof(last_dyn_error) - 1,
+            NULL) == 0)
+      snprintf(last_dyn_error, sizeof(last_dyn_error) - 1,
+            "unknown error %lu", err);
+}
+#endif
+
+/**
+ * dylib_load:
+ * @path                         : Path to libretro core library.
+ *
+ * Platform independent dylib loading.
+ *
+ * @return Library handle on success, otherwise NULL.
+ **/
+dylib_t dylib_load(const char *path)
+{
+#ifdef _WIN32
+#ifndef __WINRT__
+   int prevmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+#endif
+#ifdef __WINRT__
+   dylib_t lib;
+   /* On UWP, you can only load DLLs inside your install directory, using a special function that takes a relative path */
+   char relative_path_abbrev[PATH_MAX_LENGTH];
+   char *relative_path = relative_path_abbrev;
+   wchar_t *path_wide  = NULL;
+
+   relative_path_abbrev[0] = '\0';
+
+   if (!path_is_absolute(path))
+      RARCH_WARN("Relative path in dylib_load! This is likely an attempt to load a system library that will fail\n");
+
+   fill_pathname_abbreviate_special(relative_path_abbrev, path, sizeof(relative_path_abbrev));
+
+   /* Path to dylib_load is not inside app install directory.
+    * Loading will probably fail. */
+   if (relative_path[0] != ':' || !PATH_CHAR_IS_SLASH(relative_path[1])) { }
+   else
+      relative_path += 2;
+
+   path_wide = utf8_to_utf16_string_alloc(relative_path);
+   lib       = LoadPackagedLibrary(path_wide, 0);
+   free(path_wide);
+#elif defined(LEGACY_WIN32)
+   dylib_t lib        = LoadLibrary(path);
+#else
+   wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
+   dylib_t lib        = LoadLibraryW(path_wide);
+   free(path_wide);
+#endif
+
+#ifndef __WINRT__
+   SetErrorMode(prevmode);
+#endif
+
+   if (!lib)
+   {
+      set_dl_error();
+      return NULL;
+   }
+   last_dyn_error[0] = 0;
+#elif defined(ORBIS)
+   int res;
+   dylib_t lib = (dylib_t)sceKernelLoadStartModule(path, 0, NULL, 0, NULL, &res);
+#else
+   dylib_t lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
+#endif
+   return lib;
+}
+
+char *dylib_error(void)
+{
+#ifdef _WIN32
+   if (last_dyn_error[0])
+      return last_dyn_error;
+   return NULL;
+#else
+   return (char*)dlerror();
+#endif
+}
+
+function_t dylib_proc(dylib_t lib, const char *proc)
+{
+   function_t sym;
+
+#ifdef _WIN32
+   HMODULE mod = (HMODULE)lib;
+   if (!mod)
+   {
+#ifdef __WINRT__
+      /* GetModuleHandle is not available on UWP */
+      /* It's not possible to lookup symbols in current executable
+       * on UWP. */
+      DebugBreak();
+      return NULL;
+#else
+      mod = GetModuleHandle(NULL);
+#endif
+   }
+   if (!(sym = (function_t)GetProcAddress(mod, proc)))
+   {
+      set_dl_error();
+      return NULL;
+   }
+   last_dyn_error[0] = 0;
+#elif defined(ORBIS)
+   void *ptr_sym = NULL;
+   sym = NULL;
+
+   if (lib)
+   {
+     sceKernelDlsym((SceKernelModule)lib, proc, &ptr_sym);
+     memcpy(&sym, &ptr_sym, sizeof(void*));
+   }
+#else
+   void *ptr_sym = NULL;
+
+   if (lib)
+      ptr_sym = dlsym(lib, proc);
+   else
+   {
+      void *handle = dlopen(NULL, RTLD_LAZY);
+      if (handle)
+      {
+         ptr_sym = dlsym(handle, proc);
+         dlclose(handle);
+      }
+   }
+
+   /* Dirty hack to workaround the non-legality of
+    * (void*) -> fn-pointer casts. */
+   memcpy(&sym, &ptr_sym, sizeof(void*));
+#endif
+
+   return sym;
+}
+
+/**
+ * dylib_close:
+ * @lib                          : Library handle.
+ *
+ * Frees library handle.
+ **/
+void dylib_close(dylib_t lib)
+{
+#ifdef _WIN32
+   if (!FreeLibrary((HMODULE)lib))
+      set_dl_error();
+   last_dyn_error[0] = 0;
+#elif defined(ORBIS)
+   int res;
+   sceKernelStopUnloadModule((SceKernelModule)lib, 0, NULL, 0, NULL, &res);
+#else
+#ifndef NO_DLCLOSE
+   dlclose(lib);
+#endif
+#endif
+}
+
+#endif
diff --git a/deps/libretro-common/encodings/encoding_base64.c b/deps/libretro-common/encodings/encoding_base64.c
new file mode 100644 (file)
index 0000000..eb42243
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+  https://github.com/superwills/NibbleAndAHalf
+  base64.h -- Fast base64 encoding and decoding.
+  version 1.0.0, April 17, 2013 143a
+  Copyright (C) 2013 William Sherif
+  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.
+  William Sherif
+  will.sherif@gmail.com
+  YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
+
+
+  Modified for RetroArch formatting, logging, and header files.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <encodings/base64.h>
+
+const static char* b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* maps A=>0,B=>1.. */
+const static unsigned char unb64[]={
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,  62,   0,   0,   0,  63,  52,  53,
+ 54,  55,  56,  57,  58,  59,  60,  61,   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,   0,   0,   0,   0,   0,   0,  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,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+  0,   0,   0,   0,   0,   0,
+}; /* This array has 256 elements */
+
+/*
+   Converts binary data of length=len to base64 characters.
+   Length of the resultant string is stored in flen
+   (you must pass pointer flen).
+*/
+char* base64(const void* binaryData, int len, int *flen)
+{
+   char* res;
+   int byteNo; /* I need this after the loop */
+   const unsigned char* bin = (const unsigned char*) binaryData;
+   int rc                   = 0; /* result counter */
+   int modulusLen           = len % 3 ;
+   /* 2 gives 1 and 1 gives 2, but 0 gives 0. */
+   int pad                  = ((modulusLen&1)<<1) + ((modulusLen&2)>>1);
+
+   *flen                    = 4*(len + pad)/3;
+   if (!(res = (char*) malloc(*flen + 1))) /* and one for the NULL */
+      return 0;
+  
+   for (byteNo=0; byteNo <= len-3; byteNo+=3)
+   {
+      unsigned char BYTE0            = bin[byteNo];
+      unsigned char BYTE1            = bin[byteNo+1];
+      unsigned char BYTE2            = bin[byteNo+2];
+
+      res[rc++] = b64[BYTE0 >> 2];
+      res[rc++] = b64[((0x3&BYTE0)<<4) + (BYTE1 >> 4)];
+      res[rc++] = b64[((0x0f&BYTE1)<<2) + (BYTE2>>6)];
+      res[rc++] = b64[0x3f&BYTE2];
+   }
+  
+   if (pad==2)
+   {
+      res[rc++] = b64[bin[byteNo] >> 2];
+      res[rc++] = b64[(0x3&bin[byteNo])<<4];
+      res[rc++] = '=';
+      res[rc++] = '=';
+   }
+   else if (pad==1)
+   {
+      res[rc++] = b64[bin[byteNo] >> 2];
+      res[rc++] = b64[((0x3&bin[byteNo])<<4) + (bin[byteNo+1] >> 4)];
+      res[rc++] = b64[(0x0f&bin[byteNo+1])<<2];
+      res[rc++] = '=';
+   }
+  
+   res[rc]=0; /* NULL TERMINATOR! ;) */
+   return res;
+}
+
+unsigned char* unbase64(const char* ascii, int len, int *flen)
+{
+   int charNo;
+   unsigned char *bin;
+   const unsigned char *safeAsciiPtr = (const unsigned char*) ascii;
+   int cb                            = 0;
+   int pad                           = 0;
+
+   if (len < 2) /* 2 accesses below would be OOB (Out Of Bounds). */
+   {
+      /* catch empty string, return NULL as result. */
+      /* ERROR: You passed an invalid base64 string (too short). 
+       * You get NULL back. */
+      *flen = 0;
+      return 0;
+   }
+
+   if (safeAsciiPtr[len-1]=='=')
+      ++pad;
+   if (safeAsciiPtr[len-2]=='=')
+      ++pad;
+  
+   *flen = 3*len/4 - pad;
+   if (!(bin = (unsigned char*)malloc(*flen)))
+      return 0;
+  
+   for (charNo=0; charNo <= len-4-pad; charNo+=4)
+   {
+      int A = unb64[safeAsciiPtr[charNo]];
+      int B = unb64[safeAsciiPtr[charNo+1]];
+      int C = unb64[safeAsciiPtr[charNo+2]];
+      int D = unb64[safeAsciiPtr[charNo+3]];
+    
+      bin[cb++] = (A<<2) | (B>>4);
+      bin[cb++] = (B<<4) | (C>>2);
+      bin[cb++] = (C<<6) | (D);
+   }
+  
+   if (pad==1)
+   {
+      int A = unb64[safeAsciiPtr[charNo]];
+      int B = unb64[safeAsciiPtr[charNo+1]];
+      int C = unb64[safeAsciiPtr[charNo+2]];
+    
+      bin[cb++] = (A<<2) | (B>>4);
+      bin[cb++] = (B<<4) | (C>>2);
+   }
+   else if (pad==2)
+   {
+      int A = unb64[safeAsciiPtr[charNo]];
+      int B = unb64[safeAsciiPtr[charNo+1]];
+    
+      bin[cb++] = (A<<2) | (B>>4);
+   }
+  
+   return bin;
+}
+
diff --git a/deps/libretro-common/encodings/encoding_crc32.c b/deps/libretro-common/encodings/encoding_crc32.c
new file mode 100644 (file)
index 0000000..ab8ce82
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (encoding_crc32.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stddef.h>
+#include <encodings/crc32.h>
+#include <stdlib.h>
+
+static const uint32_t crc32_table[256] = {
+  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+  0x2d02ef8dL
+};
+
+uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len)
+{
+   crc = crc ^ 0xffffffff;
+
+   while (len--)
+      crc = crc32_table[(crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+
+   return crc ^ 0xffffffff;
+}
diff --git a/deps/libretro-common/encodings/encoding_utf.c b/deps/libretro-common/encodings/encoding_utf.c
new file mode 100644 (file)
index 0000000..f9c594d
--- /dev/null
@@ -0,0 +1,532 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (encoding_utf.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <boolean.h>
+#include <compat/strl.h>
+#include <retro_inline.h>
+
+#include <encodings/utf.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#include <windows.h>
+#elif defined(_XBOX)
+#include <xtl.h>
+#endif
+
+#define UTF8_WALKBYTE(string) (*((*(string))++))
+
+static unsigned leading_ones(uint8_t c)
+{
+   unsigned ones = 0;
+   while (c & 0x80)
+   {
+      ones++;
+      c <<= 1;
+   }
+
+   return ones;
+}
+
+/**
+ * utf8_conv_utf32:
+ *
+ * Simple implementation. Assumes the sequence is
+ * properly synchronized and terminated.
+ **/
+size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
+      const char *in, size_t in_size)
+{
+   unsigned i;
+   size_t ret = 0;
+   while (in_size && out_chars)
+   {
+      unsigned extra, shift;
+      uint32_t c;
+      uint8_t first = *in++;
+      unsigned ones = leading_ones(first);
+
+      if (ones > 6 || ones == 1) /* Invalid or desync. */
+         break;
+
+      extra = ones ? ones - 1 : ones;
+      if (1 + extra > in_size) /* Overflow. */
+         break;
+
+      shift = (extra - 1) * 6;
+      c     = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);
+
+      for (i = 0; i < extra; i++, in++, shift -= 6)
+         c |= (*in & 0x3f) << shift;
+
+      *out++   = c;
+      in_size -= 1 + extra;
+      out_chars--;
+      ret++;
+   }
+
+   return ret;
+}
+
+/**
+ * utf16_conv_utf8:
+ *
+ * Leaf function.
+ **/
+bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
+     const uint16_t *in, size_t in_size)
+{
+   size_t out_pos            = 0;
+   size_t in_pos             = 0;
+   static const 
+      uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+   for (;;)
+   {
+      unsigned num_adds;
+      uint32_t value;
+
+      if (in_pos == in_size)
+      {
+         *out_chars = out_pos;
+         return true;
+      }
+      value = in[in_pos++];
+      if (value < 0x80)
+      {
+         if (out)
+            out[out_pos] = (char)value;
+         out_pos++;
+         continue;
+      }
+
+      if (value >= 0xD800 && value < 0xE000)
+      {
+         uint32_t c2;
+
+         if (value >= 0xDC00 || in_pos == in_size)
+            break;
+         c2 = in[in_pos++];
+         if (c2 < 0xDC00 || c2 >= 0xE000)
+            break;
+         value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
+      }
+
+      for (num_adds = 1; num_adds < 5; num_adds++)
+         if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
+            break;
+      if (out)
+         out[out_pos] = (char)(utf8_limits[num_adds - 1]
+               + (value >> (6 * num_adds)));
+      out_pos++;
+      do
+      {
+         num_adds--;
+         if (out)
+            out[out_pos] = (char)(0x80
+                  + ((value >> (6 * num_adds)) & 0x3F));
+         out_pos++;
+      }while (num_adds != 0);
+   }
+
+   *out_chars = out_pos;
+   return false;
+}
+
+/**
+ * utf8cpy:
+ *
+ * Acts mostly like strlcpy.
+ *
+ * Copies the given number of UTF-8 characters,
+ * but at most @d_len bytes.
+ *
+ * Always NULL terminates. Does not copy half a character.
+ * @s is assumed valid UTF-8.
+ * Use only if @chars is considerably less than @d_len. 
+ *
+ * @return Number of bytes. 
+ **/
+size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
+{
+   const uint8_t *sb     = (const uint8_t*)s;
+   const uint8_t *sb_org = sb;
+
+   if (!s)
+      return 0;
+
+   while (*sb && chars-- > 0)
+   {
+      sb++;
+      while ((*sb & 0xC0) == 0x80)
+         sb++;
+   }
+
+   if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
+   {
+      sb = sb_org + d_len-1;
+      while ((*sb & 0xC0) == 0x80)
+         sb--;
+   }
+
+   memcpy(d, sb_org, sb-sb_org);
+   d[sb-sb_org] = '\0';
+
+   return sb-sb_org;
+}
+
+/**
+ * utf8skip:
+ *
+ * Leaf function
+ **/
+const char *utf8skip(const char *str, size_t chars)
+{
+   const uint8_t *strb = (const uint8_t*)str;
+
+   if (!chars)
+      return str;
+
+   do
+   {
+      strb++;
+      while ((*strb & 0xC0)==0x80)
+         strb++;
+      chars--;
+   }while (chars);
+
+   return (const char*)strb;
+}
+
+/**
+ * utf8len:
+ *
+ * Leaf function.
+ **/
+size_t utf8len(const char *string)
+{
+   size_t ret = 0;
+
+   if (!string)
+      return 0;
+
+   while (*string)
+   {
+      if ((*string & 0xC0) != 0x80)
+         ret++;
+      string++;
+   }
+   return ret;
+}
+
+/** 
+ * utf8_walk:
+ *
+ * Does not validate the input.
+ *
+ * Leaf function.
+ *
+ * @return Returns garbage if it's not UTF-8.
+ **/
+uint32_t utf8_walk(const char **string)
+{
+   uint8_t first = UTF8_WALKBYTE(string);
+   uint32_t ret  = 0;
+
+   if (first < 128)
+      return first;
+
+   ret    = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
+   if (first >= 0xE0)
+   {
+      ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
+      if (first >= 0xF0)
+      {
+         ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
+         return ret | (first & 7) << 18;
+      }
+      return ret | (first & 15) << 12;
+   }
+
+   return ret | (first & 31) << 6;
+}
+
+static bool utf16_to_char(uint8_t **utf_data,
+      size_t *dest_len, const uint16_t *in)
+{
+   unsigned len    = 0;
+   while (in[len] != '\0')
+      len++;
+   utf16_conv_utf8(NULL, dest_len, in, len);
+   *dest_len  += 1;
+   if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)
+      return utf16_conv_utf8(*utf_data, dest_len, in, len);
+   return false;
+}
+
+/**
+ * utf16_to_char_string:
+ **/
+bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
+{
+   size_t     dest_len     = 0;
+   uint8_t *utf16_data     = NULL;
+   bool            ret     = utf16_to_char(&utf16_data, &dest_len, in);
+
+   if (ret)
+   {
+      utf16_data[dest_len] = 0;
+      strlcpy(s, (const char*)utf16_data, len);
+   }
+
+   free(utf16_data);
+   utf16_data              = NULL;
+
+   return ret;
+}
+
+#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
+/**
+ * mb_to_mb_string_alloc:
+ *
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+static char *mb_to_mb_string_alloc(const char *str,
+      enum CodePage cp_in, enum CodePage cp_out)
+{
+   wchar_t *path_buf_wide = NULL;
+   int path_buf_wide_len  = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
+
+   /* Windows 95 will return 0 from these functions with 
+    * a UTF8 codepage set without MSLU.
+    *
+    * From an unknown MSDN version (others omit this info):
+    *   - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later: 
+    *   Translate using UTF-8. When this is set, dwFlags must be zero.
+    *   - Windows 95: Under the Microsoft Layer for Unicode, 
+    *   MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
+    */
+
+   if (!path_buf_wide_len)
+      return strdup(str);
+
+   if ((path_buf_wide = (wchar_t*)
+      calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t))))
+   {
+      MultiByteToWideChar(cp_in, 0,
+            str, -1, path_buf_wide, path_buf_wide_len);
+
+      if (*path_buf_wide)
+      {
+         int path_buf_len = WideCharToMultiByte(cp_out, 0,
+               path_buf_wide, -1, NULL, 0, NULL, NULL);
+
+         if (path_buf_len)
+         {
+            char *path_buf = (char*)
+               calloc(path_buf_len + sizeof(char), sizeof(char));
+
+            if (path_buf)
+            {
+               WideCharToMultiByte(cp_out, 0,
+                     path_buf_wide, -1, path_buf,
+                     path_buf_len, NULL, NULL);
+
+               free(path_buf_wide);
+
+               if (*path_buf)
+                  return path_buf;
+
+               free(path_buf);
+               return NULL;
+            }
+         }
+         else
+         {
+            free(path_buf_wide);
+            return strdup(str);
+         }
+      }
+
+      free(path_buf_wide);
+   }
+
+   return NULL;
+}
+#endif
+
+/**
+ * utf8_to_local_string_alloc:
+ *
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+char* utf8_to_local_string_alloc(const char *str)
+{
+   if (str && *str)
+#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
+      return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
+#else
+      return strdup(str); /* Assume string needs no modification if not on Windows */
+#endif
+   return NULL;
+}
+
+/**
+ * local_to_utf8_string_alloc:
+ *
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+char *local_to_utf8_string_alloc(const char *str)
+{
+       if (str && *str)
+#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
+               return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
+#else
+      return strdup(str); /* Assume string needs no modification if not on Windows */
+#endif
+       return NULL;
+}
+
+/**
+ * utf8_to_utf16_string_alloc:
+ * 
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+wchar_t* utf8_to_utf16_string_alloc(const char *str)
+{
+#ifdef _WIN32
+   int len        = 0;
+#else
+   size_t len     = 0;
+#endif
+   wchar_t *buf   = NULL;
+
+   if (!str || !*str)
+      return NULL;
+
+#ifdef _WIN32
+   if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
+   {
+      if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
+         return NULL;
+
+      if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len)) < 0)
+      {
+         free(buf);
+         return NULL;
+      }
+   }
+   else
+   {
+      /* Fallback to ANSI codepage instead */
+      if ((len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))
+      {
+         if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
+            return NULL;
+
+         if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len)) < 0)
+         {
+            free(buf);
+            return NULL;
+         }
+      }
+   }
+#else
+   /* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
+   if ((len = mbstowcs(NULL, str, 0) + 1))
+   {
+      if (!(buf = (wchar_t*)calloc(len, sizeof(wchar_t))))
+         return NULL;
+
+      if ((mbstowcs(buf, str, len)) == (size_t)-1)
+      {
+         free(buf);
+         return NULL;
+      }
+   }
+#endif
+
+   return buf;
+}
+
+/**
+ * utf16_to_utf8_string_alloc:
+ *
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+char* utf16_to_utf8_string_alloc(const wchar_t *str)
+{
+#ifdef _WIN32
+   int len        = 0;
+#else
+   size_t len     = 0;
+#endif
+   char *buf      = NULL;
+
+   if (!str || !*str)
+      return NULL;
+
+#ifdef _WIN32
+   {
+      UINT code_page = CP_UTF8;
+
+      /* fallback to ANSI codepage instead */
+      if (!(len = WideCharToMultiByte(code_page,
+            0, str, -1, NULL, 0, NULL, NULL)))
+      {
+         code_page   = CP_ACP;
+         len         = WideCharToMultiByte(code_page,
+               0, str, -1, NULL, 0, NULL, NULL);
+      }
+
+      if (!(buf = (char*)calloc(len, sizeof(char))))
+         return NULL;
+
+      if (WideCharToMultiByte(code_page,
+            0, str, -1, buf, len, NULL, NULL) < 0)
+      {
+         free(buf);
+         return NULL;
+      }
+   }
+#else
+   /* NOTE: For now, assume non-Windows platforms' 
+    * locale is already UTF-8. */
+   if ((len = wcstombs(NULL, str, 0) + 1))
+   {
+      if (!(buf = (char*)calloc(len, sizeof(char))))
+         return NULL;
+
+      if (wcstombs(buf, str, len) == (size_t)-1)
+      {
+         free(buf);
+         return NULL;
+      }
+   }
+#endif
+
+   return buf;
+}
diff --git a/deps/libretro-common/features/features_cpu.c b/deps/libretro-common/features/features_cpu.c
new file mode 100644 (file)
index 0000000..80fe2c1
--- /dev/null
@@ -0,0 +1,920 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (features_cpu.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#if defined(_WIN32)
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <compat/strl.h>
+#include <streams/file_stream.h>
+#include <libretro.h>
+#include <features/features_cpu.h>
+#include <retro_timers.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#include <windows.h>
+#endif
+
+#ifdef __PSL1GHT__
+#include <lv2/systime.h>
+#endif
+
+#if defined(_XBOX360)
+#include <PPCIntrinsics.h>
+#elif !defined(__MACH__) && (defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC64__) || defined(__powerpc64__))
+#ifndef _PPU_INTRINSICS_H
+#include <ppu_intrinsics.h>
+#endif
+#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
+/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
+#include <time.h>
+#endif
+
+#if defined(__QNX__) && !defined(CLOCK_MONOTONIC)
+#define CLOCK_MONOTONIC 2
+#endif
+
+#if defined(PSP)
+#include <pspkernel.h>
+#endif
+
+#if defined(PSP) || defined(__PSL1GHT__)
+#include <sys/time.h>
+#endif
+
+#if defined(PSP)
+#include <psprtc.h>
+#endif
+
+#if defined(VITA)
+#include <psp2/kernel/processmgr.h>
+#include <psp2/rtc.h>
+#endif
+
+#if defined(ORBIS)
+#include <orbis/libkernel.h>
+#endif
+
+#if defined(PS2)
+#include <ps2sdkapi.h>
+#endif
+
+#if !defined(__PSL1GHT__) && defined(__PS3__)
+#include <sys/sys_time.h>
+#endif
+
+#ifdef GEKKO
+#include <ogc/lwp_watchdog.h>
+#endif
+
+#ifdef WIIU
+#include <wiiu/os/time.h>
+#endif
+
+#if defined(HAVE_LIBNX)
+#include <switch.h>
+#elif defined(SWITCH)
+#include <libtransistor/types.h>
+#include <libtransistor/svc.h>
+#endif
+
+#if defined(_3DS)
+#include <3ds/svc.h>
+#include <3ds/os.h>
+#include <3ds/services/cfgu.h>
+#endif
+
+/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
+#ifdef __MACH__
+#include <sys/time.h>
+
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 0
+#endif
+
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME 0
+#endif
+
+/**
+ * TODO/FIXME: clock_gettime function is part of iOS 10 now
+ **/
+static int ra_clock_gettime(int clk_ik, struct timespec *t)
+{
+   struct timeval now;
+   int rv     = gettimeofday(&now, NULL);
+   if (rv)
+      return rv;
+   t->tv_sec  = now.tv_sec;
+   t->tv_nsec = now.tv_usec * 1000;
+   return 0;
+}
+#endif
+
+#if defined(__MACH__) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
+#else
+#define ra_clock_gettime clock_gettime
+#endif
+
+#ifdef EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#if defined(BSD) || defined(__APPLE__)
+#include <sys/sysctl.h>
+#endif
+
+#include <string.h>
+
+/**
+ * cpu_features_get_perf_counter:
+ *
+ * Gets performance counter.
+ *
+ * @return Performance counter.
+ **/
+retro_perf_tick_t cpu_features_get_perf_counter(void)
+{
+   retro_perf_tick_t time_ticks = 0;
+#if defined(_WIN32)
+   long tv_sec, tv_usec;
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+   static const unsigned __int64 epoch = 11644473600000000;
+#else
+   static const unsigned __int64 epoch = 11644473600000000ULL;
+#endif
+   FILETIME file_time;
+   SYSTEMTIME system_time;
+   ULARGE_INTEGER ularge;
+
+   GetSystemTime(&system_time);
+   SystemTimeToFileTime(&system_time, &file_time);
+   ularge.LowPart  = file_time.dwLowDateTime;
+   ularge.HighPart = file_time.dwHighDateTime;
+
+   tv_sec     = (long)((ularge.QuadPart - epoch) / 10000000L);
+   tv_usec    = (long)(system_time.wMilliseconds * 1000);
+   time_ticks = (1000000 * tv_sec + tv_usec);
+#elif defined(GEKKO)
+   time_ticks = gettime();
+#elif !defined(__MACH__) && (defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__) || defined(__PPC64__) || defined(__powerpc64__))
+   time_ticks = __mftb();
+#elif (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0) || defined(__QNX__) || defined(ANDROID)
+   struct timespec tv;
+   if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
+      time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
+         (retro_perf_tick_t)tv.tv_nsec;
+
+#elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)
+   __asm__ volatile ("rdtsc" : "=A" (time_ticks));
+#elif defined(__GNUC__) && defined(__x86_64__) || defined(_M_IX86)
+   unsigned a, d;
+   __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
+   time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
+#elif defined(__ARM_ARCH_6__)
+   __asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
+#elif defined(__aarch64__)
+   __asm__ volatile( "mrs %0, cntvct_el0" : "=r"(time_ticks) );
+#elif defined(PSP) || defined(VITA)
+   time_ticks = sceKernelGetSystemTimeWide();
+#elif defined(ORBIS)
+   sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);
+#elif defined(PS2)
+   time_ticks = ps2_clock();
+#elif defined(_3DS)
+   time_ticks = svcGetSystemTick();
+#elif defined(WIIU)
+   time_ticks = OSGetSystemTime();
+#elif defined(HAVE_LIBNX)
+   time_ticks = armGetSystemTick();
+#elif defined(EMSCRIPTEN)
+   time_ticks = emscripten_get_now() * 1000;
+#endif
+
+   return time_ticks;
+}
+
+/**
+ * cpu_features_get_time_usec:
+ *
+ * Gets time in microseconds.
+ *
+ * @return Time in microseconds.
+ **/
+retro_time_t cpu_features_get_time_usec(void)
+{
+#if defined(_WIN32)
+   static LARGE_INTEGER freq;
+   LARGE_INTEGER count;
+
+   /* Frequency is guaranteed to not change. */
+   if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
+      return 0;
+
+   if (!QueryPerformanceCounter(&count))
+      return 0;
+   return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);
+#elif defined(__PSL1GHT__)
+   return sysGetSystemTime();
+#elif !defined(__PSL1GHT__) && defined(__PS3__)
+   return sys_time_get_system_time();
+#elif defined(GEKKO)
+   return ticks_to_microsecs(gettime());
+#elif defined(WIIU)
+   return ticks_to_us(OSGetSystemTime());
+#elif defined(SWITCH) || defined(HAVE_LIBNX)
+   return (svcGetSystemTick() * 10) / 192;
+#elif defined(_3DS)
+   return osGetTime() * 1000;
+#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
+   struct timespec tv;
+   if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
+      return 0;
+   return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
+#elif defined(EMSCRIPTEN)
+   return emscripten_get_now() * 1000;
+#elif defined(PS2)
+   return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;
+#elif defined(VITA) || defined(PSP)
+   return sceKernelGetSystemTimeWide();
+#elif defined(DJGPP)
+   return uclock() * 1000000LL / UCLOCKS_PER_SEC;
+#elif defined(ORBIS)
+   return sceKernelGetProcessTime();
+#else
+#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
+#endif
+}
+
+#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)
+#define CPU_X86
+#endif
+
+#if defined(_MSC_VER) && !defined(_XBOX)
+#if (_MSC_VER > 1310)
+#include <intrin.h>
+#endif
+#endif
+
+#if defined(CPU_X86) && !defined(__MACH__)
+void x86_cpuid(int func, int flags[4])
+{
+   /* On Android, we compile RetroArch with PIC, and we
+    * are not allowed to clobber the ebx register. */
+#ifdef __x86_64__
+#define REG_b "rbx"
+#define REG_S "rsi"
+#else
+#define REG_b "ebx"
+#define REG_S "esi"
+#endif
+
+#if defined(__GNUC__)
+   __asm__ volatile (
+         "mov %%" REG_b ", %%" REG_S "\n"
+         "cpuid\n"
+         "xchg %%" REG_b ", %%" REG_S "\n"
+         : "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
+         : "a"(func));
+#elif defined(_MSC_VER)
+   __cpuid(flags, func);
+#else
+#ifndef NDEBUG
+   printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
+#endif
+   memset(flags, 0, 4 * sizeof(int));
+#endif
+}
+
+/* Only runs on i686 and above. Needs to be conditionally run. */
+static uint64_t xgetbv_x86(uint32_t idx)
+{
+#if defined(__GNUC__)
+   uint32_t eax, edx;
+   __asm__ volatile (
+         /* Older GCC versions (Apple's GCC for example) do
+          * not understand xgetbv instruction.
+          * Stamp out the machine code directly.
+          */
+         ".byte 0x0f, 0x01, 0xd0\n"
+         : "=a"(eax), "=d"(edx) : "c"(idx));
+   return ((uint64_t)edx << 32) | eax;
+#elif _MSC_FULL_VER >= 160040219
+   /* Intrinsic only works on 2010 SP1 and above. */
+   return _xgetbv(idx);
+#else
+#ifndef NDEBUG
+   printf("Unknown compiler. Cannot check xgetbv bits.\n");
+#endif
+   return 0;
+#endif
+}
+#endif
+
+#if defined(__ARM_NEON__)
+#if defined(__arm__)
+static void arm_enable_runfast_mode(void)
+{
+   /* RunFast mode. Enables flush-to-zero and some
+    * floating point optimizations. */
+   static const unsigned x = 0x04086060;
+   static const unsigned y = 0x03000000;
+   int r;
+   __asm__ volatile(
+         "fmrx %0, fpscr   \n\t" /* r0 = FPSCR */
+         "and  %0, %0, %1  \n\t" /* r0 = r0 & 0x04086060 */
+         "orr  %0, %0, %2  \n\t" /* r0 = r0 | 0x03000000 */
+         "fmxr fpscr, %0   \n\t" /* FPSCR = r0 */
+         : "=r"(r)
+         : "r"(x), "r"(y)
+        );
+}
+#endif
+#endif
+
+#if defined(__linux__) && !defined(CPU_X86)
+static unsigned char check_arm_cpu_feature(const char* feature)
+{
+   char line[1024];
+   unsigned char status = 0;
+   RFILE *fp = filestream_open("/proc/cpuinfo",
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+   if (!fp)
+      return 0;
+
+   while (filestream_gets(fp, line, sizeof(line)))
+   {
+      if (strncmp(line, "Features\t: ", 11))
+         continue;
+
+      if (strstr(line + 11, feature))
+         status = 1;
+
+      break;
+   }
+
+   filestream_close(fp);
+
+   return status;
+}
+
+#if !defined(_SC_NPROCESSORS_ONLN)
+/**
+ * parse_decimal:
+ *
+ * Parse an decimal integer starting from 'input', but not going further
+ * than 'limit'. Return the value into '*result'.
+ *
+ * NOTE: Does not skip over leading spaces, or deal with sign characters.
+ * NOTE: Ignores overflows.
+ *
+ * The function returns NULL in case of error (bad format), or the new
+ * position after the decimal number in case of success (which will always
+ * be <= 'limit').
+ *
+ * Leaf function.
+ **/
+static const char *parse_decimal(const char* input,
+      const char* limit, int* result)
+{
+    const char* p = input;
+    int       val = 0;
+
+    while (p < limit)
+    {
+        int d = (*p - '0');
+        if ((unsigned)d >= 10U)
+            break;
+        val = val*10 + d;
+        p++;
+    }
+    if (p == input)
+        return NULL;
+
+    *result = val;
+    return p;
+}
+
+/**
+ * cpulist_parse:
+ * Parse a textual list of cpus and store the result inside a CpuList object.
+ * Input format is the following:
+ * - comma-separated list of items (no spaces)
+ * - each item is either a single decimal number (cpu index), or a range made
+ *   of two numbers separated by a single dash (-). Ranges are inclusive.
+ *
+ * Examples:   0
+ *             2,4-127,128-143
+ *             0-1
+ **/
+static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
+{
+   const char* p   = (const char*)buf;
+   const char* end = p + length;
+
+   /* NOTE: the input line coming from sysfs typically contains a
+    * trailing newline, so take care of it in the code below
+    */
+   while (p < end && *p != '\n')
+   {
+      int val, start_value, end_value;
+      /* Find the end of current item, and put it into 'q' */
+      const char *q = (const char*)memchr(p, ',', end-p);
+
+      if (!q)
+         q = end;
+
+      /* Get first value */
+      if (!(p = parse_decimal(p, q, &start_value)))
+         return;
+
+      end_value = start_value;
+
+      /* If we're not at the end of the item, expect a dash and
+       * and integer; extract end value.
+       */
+      if (p < q && *p == '-')
+      {
+         if (!(p = parse_decimal(p+1, q, &end_value)))
+            return;
+      }
+
+      /* Set bits CPU list bits */
+      for (val = start_value; val <= end_value; val++)
+      {
+         if ((unsigned)val < 32)
+            list->mask |= (uint32_t)(UINT32_C(1) << val);
+      }
+
+      /* Jump to next item */
+      p = q;
+      if (p < end)
+         p++;
+   }
+}
+
+/**
+ * cpulist_read_from:
+ *
+ * Read a CPU list from one sysfs file
+ **/
+static void cpulist_read_from(CpuList* list, const char* filename)
+{
+   ssize_t length;
+   char *buf  = NULL;
+
+   list->mask = 0;
+
+   if (filestream_read_file(filename, (void**)&buf, &length) != 1)
+      return;
+
+   cpulist_parse(list, &buf, length);
+   if (buf)
+      free(buf);
+   buf = NULL;
+}
+#endif
+
+#endif
+
+/**
+ * cpu_features_get_core_amount:
+ *
+ * Gets the amount of available CPU cores.
+ *
+ * @return Amount of CPU cores available.
+ **/
+unsigned cpu_features_get_core_amount(void)
+{
+#if defined(_WIN32) && !defined(_XBOX)
+   /* Win32 */
+   SYSTEM_INFO sysinfo;
+#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+   GetNativeSystemInfo(&sysinfo);
+#else
+   GetSystemInfo(&sysinfo);
+#endif
+   return sysinfo.dwNumberOfProcessors;
+#elif defined(GEKKO)
+   return 1;
+#elif defined(PSP) || defined(PS2)
+   return 1;
+#elif defined(__PSL1GHT__) || !defined(__PSL1GHT__) && defined(__PS3__)
+   return 1; /* Only one PPU, SPUs don't really count */
+#elif defined(VITA)
+   return 4;
+#elif defined(HAVE_LIBNX) || defined(SWITCH)
+   return 4;
+#elif defined(_3DS)
+   u8 device_model = 0xFF;
+   CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
+   switch (device_model)
+   {
+               case 0:
+               case 1:
+               case 3:
+                       /*Old 3/2DS*/
+                       return 2;
+
+               case 2:
+               case 4:
+               case 5:
+                       /*New 3/2DS*/
+                       return 4;
+
+               default:
+                       /*Unknown Device Or Check Failed*/
+                       break;
+   }
+   return 1;
+#elif defined(WIIU)
+   return 3;
+#elif defined(_SC_NPROCESSORS_ONLN)
+   /* Linux, most UNIX-likes. */
+   long ret = sysconf(_SC_NPROCESSORS_ONLN);
+   if (ret <= 0)
+      return (unsigned)1;
+   return (unsigned)ret;
+#elif defined(BSD) || defined(__APPLE__)
+   /* BSD */
+   /* Copypasta from stackoverflow, dunno if it works. */
+   int num_cpu = 0;
+   int mib[4];
+   size_t len = sizeof(num_cpu);
+
+   mib[0] = CTL_HW;
+   mib[1] = HW_AVAILCPU;
+   sysctl(mib, 2, &num_cpu, &len, NULL, 0);
+   if (num_cpu < 1)
+   {
+      mib[1] = HW_NCPU;
+      sysctl(mib, 2, &num_cpu, &len, NULL, 0);
+      if (num_cpu < 1)
+         num_cpu = 1;
+   }
+   return num_cpu;
+#elif defined(__linux__)
+   CpuList  cpus_present[1];
+   CpuList  cpus_possible[1];
+   int amount = 0;
+
+   cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
+   cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
+
+   /* Compute the intersection of both sets to get the actual number of
+    * CPU cores that can be used on this device by the kernel.
+    */
+   cpus_present->mask &= cpus_possible->mask;
+   amount              = __builtin_popcount(cpus_present->mask);
+
+   if (amount == 0)
+      return 1;
+   return amount;
+#elif defined(_XBOX360)
+   return 3;
+#else
+   /* No idea, assume single core. */
+   return 1;
+#endif
+}
+
+/* According to http://en.wikipedia.org/wiki/CPUID */
+#define VENDOR_INTEL_b  0x756e6547
+#define VENDOR_INTEL_c  0x6c65746e
+#define VENDOR_INTEL_d  0x49656e69
+
+/**
+ * cpu_features_get:
+ *
+ * Gets CPU features..
+ *
+ * @return Bitmask of all CPU features available.
+ **/
+uint64_t cpu_features_get(void)
+{
+   uint64_t cpu        = 0;
+#if defined(CPU_X86) && !defined(__MACH__)
+   int vendor_is_intel = 0;
+   const int avx_flags = (1 << 27) | (1 << 28);
+#endif
+#if defined(__MACH__)
+   size_t len          = sizeof(size_t);
+
+   if (sysctlbyname("hw.optional.floatingpoint", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_CMOV;
+
+#if defined(CPU_X86)
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.mmx", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_MMX | RETRO_SIMD_MMXEXT;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.sse", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_SSE;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.sse2", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_SSE2;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.sse3", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_SSE3;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.supplementalsse3", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_SSSE3;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.sse4_1", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_SSE4;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.sse4_2", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_SSE42;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.aes", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_AES;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.avx1_0", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_AVX;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.avx2_0", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_AVX2;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.altivec", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_VMX;
+
+#else
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.neon", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_NEON;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.neon_fp16", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_VFPV3;
+
+   len            = sizeof(size_t);
+   if (sysctlbyname("hw.optional.neon_hpfp", NULL, &len, NULL, 0) == 0)
+      cpu |= RETRO_SIMD_VFPV4;
+#endif
+#elif defined(_XBOX1)
+   cpu |= RETRO_SIMD_MMX | RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
+#elif defined(CPU_X86)
+   unsigned max_flag   = 0;
+   int flags[4];
+   int vendor_shuffle[3];
+   char vendor[13];
+   x86_cpuid(0, flags);
+   vendor_shuffle[0] = flags[1];
+   vendor_shuffle[1] = flags[3];
+   vendor_shuffle[2] = flags[2];
+
+   vendor[0]         = '\0';
+   memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));
+
+   /* printf("[CPUID]: Vendor: %s\n", vendor); */
+
+   vendor_is_intel = (
+         flags[1] == VENDOR_INTEL_b &&
+         flags[2] == VENDOR_INTEL_c &&
+         flags[3] == VENDOR_INTEL_d);
+
+   max_flag = flags[0];
+   if (max_flag < 1) /* Does CPUID not support func = 1? (unlikely ...) */
+      return 0;
+
+   x86_cpuid(1, flags);
+
+   if (flags[3] & (1 << 15))
+      cpu |= RETRO_SIMD_CMOV;
+
+   if (flags[3] & (1 << 23))
+      cpu |= RETRO_SIMD_MMX;
+
+   /* SSE also implies MMXEXT (according to FFmpeg source). */
+   if (flags[3] & (1 << 25))
+      cpu |= RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;
+
+   if (flags[3] & (1 << 26))
+      cpu |= RETRO_SIMD_SSE2;
+
+   if (flags[2] & (1 << 0))
+      cpu |= RETRO_SIMD_SSE3;
+
+   if (flags[2] & (1 << 9))
+      cpu |= RETRO_SIMD_SSSE3;
+
+   if (flags[2] & (1 << 19))
+      cpu |= RETRO_SIMD_SSE4;
+
+   if (flags[2] & (1 << 20))
+      cpu |= RETRO_SIMD_SSE42;
+
+   if ((flags[2] & (1 << 23)))
+      cpu |= RETRO_SIMD_POPCNT;
+
+   if (vendor_is_intel && (flags[2] & (1 << 22)))
+      cpu |= RETRO_SIMD_MOVBE;
+
+   if (flags[2] & (1 << 25))
+      cpu |= RETRO_SIMD_AES;
+
+   /* Must only perform xgetbv check if we have
+    * AVX CPU support (guaranteed to have at least i686). */
+   if (((flags[2] & avx_flags) == avx_flags)
+         && ((xgetbv_x86(0) & 0x6) == 0x6))
+      cpu |= RETRO_SIMD_AVX;
+
+   if (max_flag >= 7)
+   {
+      x86_cpuid(7, flags);
+      if (flags[1] & (1 << 5))
+         cpu |= RETRO_SIMD_AVX2;
+   }
+
+   x86_cpuid(0x80000000, flags);
+   max_flag = flags[0];
+   if (max_flag >= 0x80000001u)
+   {
+      x86_cpuid(0x80000001, flags);
+      if (flags[3] & (1 << 23))
+         cpu |= RETRO_SIMD_MMX;
+      if (flags[3] & (1 << 22))
+         cpu |= RETRO_SIMD_MMXEXT;
+   }
+#elif defined(__linux__)
+   if (check_arm_cpu_feature("neon"))
+   {
+      cpu |= RETRO_SIMD_NEON;
+#if defined(__ARM_NEON__) && defined(__arm__)
+      arm_enable_runfast_mode();
+#endif
+   }
+
+   if (check_arm_cpu_feature("vfpv3"))
+      cpu |= RETRO_SIMD_VFPV3;
+
+   if (check_arm_cpu_feature("vfpv4"))
+      cpu |= RETRO_SIMD_VFPV4;
+
+   if (check_arm_cpu_feature("asimd"))
+   {
+      cpu |= RETRO_SIMD_ASIMD;
+#ifdef __ARM_NEON__
+      cpu |= RETRO_SIMD_NEON;
+#if defined(__arm__)
+      arm_enable_runfast_mode();
+#endif
+#endif
+   }
+
+#if 0
+    check_arm_cpu_feature("swp");
+    check_arm_cpu_feature("half");
+    check_arm_cpu_feature("thumb");
+    check_arm_cpu_feature("fastmult");
+    check_arm_cpu_feature("vfp");
+    check_arm_cpu_feature("edsp");
+    check_arm_cpu_feature("thumbee");
+    check_arm_cpu_feature("tls");
+    check_arm_cpu_feature("idiva");
+    check_arm_cpu_feature("idivt");
+#endif
+
+#elif defined(__ARM_NEON__)
+   cpu |= RETRO_SIMD_NEON;
+#if defined(__arm__)
+   arm_enable_runfast_mode();
+#endif
+#elif defined(__ALTIVEC__)
+   cpu |= RETRO_SIMD_VMX;
+#elif defined(XBOX360)
+   cpu |= RETRO_SIMD_VMX128;
+#elif defined(PSP) || defined(PS2)
+   cpu |= RETRO_SIMD_VFPU;
+#elif defined(GEKKO)
+   cpu |= RETRO_SIMD_PS;
+#endif
+
+   return cpu;
+}
+
+void cpu_features_get_model_name(char *name, int len)
+{
+#if defined(CPU_X86) && !defined(__MACH__)
+   union {
+      int32_t i[4];
+      uint32_t u[4];
+      uint8_t s[16];
+   } flags;
+   int i, j;
+   int pos = 0;
+   bool start = false;
+
+   if (!name)
+      return;
+
+   x86_cpuid(0x80000000, flags.i);
+
+   /* Check for additional cpuid attributes availability */
+   if (flags.u[0] < 0x80000004)
+      return;
+
+   for (i = 0; i < 3; i++)
+   {
+      memset(flags.i, 0, sizeof(flags.i));
+      x86_cpuid(0x80000002 + i, flags.i);
+
+      for (j = 0; j < (int)sizeof(flags.s); j++)
+      {
+         if (!start && flags.s[j] == ' ')
+            continue;
+         else
+            start = true;
+
+         if (pos == len - 1)
+         {
+            /* truncate if we ran out of room */
+            name[pos] = '\0';
+            goto end;
+         }
+
+         name[pos++] = flags.s[j];
+      }
+   }
+end:
+   /* terminate our string */
+   if (pos < len)
+      name[pos] = '\0';
+#elif defined(__MACH__)
+   if (!name)
+      return;
+   {
+      size_t len_size = len;
+      sysctlbyname("machdep.cpu.brand_string", name, &len_size, NULL, 0);
+   }
+#elif defined(__linux__)
+   if (!name)
+      return;
+   {
+      char *model_name, line[128];
+      RFILE *fp = filestream_open("/proc/cpuinfo",
+            RETRO_VFS_FILE_ACCESS_READ,
+            RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+      if (!fp)
+         return;
+
+      while (filestream_gets(fp, line, sizeof(line)))
+      {
+         if (strncmp(line, "model name", 10))
+            continue;
+
+         if ((model_name = strstr(line + 10, ": ")))
+         {
+            model_name += 2;
+            strncpy(name, model_name, len);
+            name[len - 1] = '\0';
+         }
+
+         break;
+      }
+
+      filestream_close(fp);
+   }
+#else
+   if (!name)
+      return;
+   return;
+#endif
+}
diff --git a/deps/libretro-common/file/archive_file.c b/deps/libretro-common/file/archive_file.c
new file mode 100644 (file)
index 0000000..5a9c21a
--- /dev/null
@@ -0,0 +1,734 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (archive_file.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <compat/strl.h>
+#include <file/archive_file.h>
+#include <file/file_path.h>
+#include <streams/file_stream.h>
+#include <retro_miscellaneous.h>
+#include <lists/string_list.h>
+#include <string/stdstring.h>
+
+#ifdef HAVE_MMAP
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#endif
+
+static int file_archive_get_file_list_cb(
+      const char *path,
+      const char *valid_exts,
+      const uint8_t *cdata,
+      unsigned cmode,
+      uint32_t csize,
+      uint32_t size,
+      uint32_t checksum,
+      struct archive_extract_userdata *userdata)
+{
+   union string_list_elem_attr attr;
+   attr.i = 0;
+
+   if (valid_exts)
+   {
+      size_t path_len              = strlen(path);
+      /* Checks if this entry is a directory or a file. */
+      char last_char               = path[path_len - 1];
+      struct string_list ext_list  = {0};
+
+      /* Skip if directory. */
+      if (last_char == '/' || last_char == '\\' )
+         return 1;
+      
+      string_list_initialize(&ext_list);
+      if (string_split_noalloc(&ext_list, valid_exts, "|"))
+      {
+         const char *file_ext = path_get_extension(path);
+
+         if (!file_ext)
+         {
+            string_list_deinitialize(&ext_list);
+            return 1;
+         }
+
+         if (!string_list_find_elem_prefix(&ext_list, ".", file_ext))
+         {
+            /* keep iterating */
+            string_list_deinitialize(&ext_list);
+            return -1;
+         }
+
+         attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;
+      }
+
+      string_list_deinitialize(&ext_list);
+   }
+
+   return string_list_append(userdata->list, path, attr);
+}
+
+static int file_archive_extract_cb(const char *name, const char *valid_exts,
+      const uint8_t *cdata,
+      unsigned cmode, uint32_t csize, uint32_t size,
+      uint32_t checksum, struct archive_extract_userdata *userdata)
+{
+   const char *ext                   = path_get_extension(name);
+
+   /* Extract first file that matches our list. */
+   if (ext && string_list_find_elem(userdata->ext, ext))
+   {
+      char new_path[PATH_MAX_LENGTH];
+      const char *delim;
+
+      if ((delim = path_get_archive_delim(userdata->archive_path)))
+      {
+         if (!string_is_equal_noncase(
+                  userdata->current_file_path, delim + 1))
+           return 1; /* keep searching for the right file */
+      }
+
+      if (userdata->extraction_directory)
+         fill_pathname_join_special(new_path, userdata->extraction_directory,
+               path_basename(name), sizeof(new_path));
+      else
+         fill_pathname_resolve_relative(new_path, userdata->archive_path,
+               path_basename(name), sizeof(new_path));
+
+      if (file_archive_perform_mode(new_path,
+                valid_exts, cdata, cmode, csize, size,
+                checksum, userdata))
+      {
+         userdata->found_file = true;
+         userdata->first_extracted_file_path = strdup(new_path);
+      }
+
+      return 0;
+   }
+
+   return 1;
+}
+
+static int file_archive_parse_file_init(file_archive_transfer_t *state,
+      const char *file)
+{
+   char path[PATH_MAX_LENGTH];
+   char *last                 = NULL;
+
+   strlcpy(path, file, sizeof(path));
+
+   if ((last = (char*)path_get_archive_delim(path)))
+      *last  = '\0';
+
+   if (!(state->backend = file_archive_get_file_backend(path)))
+      return -1;
+
+   /* Failed to open archive. */
+   if (!(state->archive_file = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
+      return -1;
+
+   state->archive_size = filestream_get_size(state->archive_file);
+
+#ifdef HAVE_MMAP
+   if (state->archive_size <= (256*1024*1024))
+   {
+      state->archive_mmap_fd = open(path, O_RDONLY);
+      if (state->archive_mmap_fd)
+      {
+         state->archive_mmap_data = (uint8_t*)mmap(NULL, (size_t)state->archive_size,
+               PROT_READ, MAP_SHARED, state->archive_mmap_fd, 0);
+
+         if (state->archive_mmap_data == (uint8_t*)MAP_FAILED)
+         {
+            close(state->archive_mmap_fd);
+            state->archive_mmap_fd = 0;
+            state->archive_mmap_data = NULL;
+         }
+      }
+   }
+#endif
+
+   state->step_current = 0;
+   state->step_total   = 0;
+
+   return state->backend->archive_parse_file_init(state, path);
+}
+
+/**
+ * file_archive_decompress_data_to_file:
+ * @path                        : filename path of archive.
+ * @size                        : output file size
+ * @checksum                    : CRC32 checksum from input data.
+ *
+ * Write data to file.
+ *
+ * Returns: true (1) on success, otherwise false (0).
+ **/
+static int file_archive_decompress_data_to_file(
+      file_archive_transfer_t *transfer,
+      file_archive_file_handle_t *handle,
+      const char *path,
+      uint32_t size,
+      uint32_t checksum)
+{
+   if (!handle)
+      return 0;
+
+#if 0
+   handle->real_checksum = transfer->backend->stream_crc_calculate(
+         0, handle->data, size);
+   if (handle->real_checksum != checksum)
+   {
+      /* File CRC difers from archive CRC. */
+      printf("File CRC differs from archive CRC. File: 0x%x, Archive: 0x%x.\n",
+            (unsigned)handle->real_checksum, (unsigned)checksum);
+   }
+#endif
+
+   if (!filestream_write_file(path, handle->data, size))
+      return 0;
+
+   return 1;
+}
+
+void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state)
+{
+   if (!state || !state->archive_file)
+      return;
+
+   state->type = ARCHIVE_TRANSFER_DEINIT;
+   file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL);
+}
+
+int file_archive_parse_file_iterate(
+      file_archive_transfer_t *state,
+      bool *returnerr,
+      const char *file,
+      const char *valid_exts,
+      file_archive_file_cb file_cb,
+      struct archive_extract_userdata *userdata)
+{
+   if (!state)
+      return -1;
+
+   switch (state->type)
+   {
+      case ARCHIVE_TRANSFER_NONE:
+         break;
+      case ARCHIVE_TRANSFER_INIT:
+         if (file_archive_parse_file_init(state, file) == 0)
+         {
+            if (userdata)
+            {
+               userdata->transfer = state;
+               strlcpy(userdata->archive_path, file,
+                     sizeof(userdata->archive_path));
+            }
+            state->type = ARCHIVE_TRANSFER_ITERATE;
+         }
+         else
+            state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
+         break;
+      case ARCHIVE_TRANSFER_ITERATE:
+         if (state->backend)
+         {
+            int ret = state->backend->archive_parse_file_iterate_step(
+                  state->context, valid_exts, userdata, file_cb);
+
+            if (ret == 1)
+               state->step_current++; /* found another file */
+            if (ret != 1)
+               state->type = ARCHIVE_TRANSFER_DEINIT;
+            if (ret == -1)
+               state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
+
+            /* early return to prevent deinit from never firing */
+            return 0;
+         }
+         return -1;
+      case ARCHIVE_TRANSFER_DEINIT_ERROR:
+         *returnerr = false;
+      case ARCHIVE_TRANSFER_DEINIT:
+         if (state->context)
+         {
+            if (state->backend->archive_parse_file_free)
+               state->backend->archive_parse_file_free(state->context);
+            state->context = NULL;
+         }
+
+         if (state->archive_file)
+         {
+            filestream_close(state->archive_file);
+            state->archive_file = NULL;
+         }
+
+#ifdef HAVE_MMAP
+         if (state->archive_mmap_data)
+         {
+            munmap(state->archive_mmap_data, (size_t)state->archive_size);
+            close(state->archive_mmap_fd);
+            state->archive_mmap_fd = 0;
+            state->archive_mmap_data = NULL;
+         }
+#endif
+
+         if (userdata)
+            userdata->transfer = NULL;
+         break;
+   }
+
+   if (  state->type == ARCHIVE_TRANSFER_DEINIT ||
+         state->type == ARCHIVE_TRANSFER_DEINIT_ERROR)
+      return -1;
+
+   return 0;
+}
+
+/**
+ * file_archive_walk:
+ * @file                        : filename path of archive
+ * @valid_exts                  : Valid extensions of archive to be parsed.
+ *                                If NULL, allow all.
+ * @file_cb                     : file_cb function pointer
+ * @userdata                    : userdata to pass to file_cb function pointer.
+ *
+ * Low-level file parsing. Enumerates over all files and calls
+ * file_cb with userdata.
+ *
+ * Returns: true (1) on success, otherwise false (0).
+ **/
+static bool file_archive_walk(const char *file, const char *valid_exts,
+      file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)
+{
+   file_archive_transfer_t state;
+   bool returnerr          = true;
+
+   state.type              = ARCHIVE_TRANSFER_INIT;
+   state.archive_file      = NULL;
+#ifdef HAVE_MMAP
+   state.archive_mmap_fd   = 0;
+   state.archive_mmap_data = NULL;
+#endif
+   state.archive_size      = 0;
+   state.context           = NULL;
+   state.step_total        = 0;
+   state.step_current      = 0;
+   state.backend           = NULL;
+
+   for (;;)
+   {
+      if (file_archive_parse_file_iterate(&state, &returnerr, file,
+            valid_exts, file_cb, userdata) != 0)
+         break;
+   }
+
+   return returnerr;
+}
+
+int file_archive_parse_file_progress(file_archive_transfer_t *state)
+{
+   if (!state || state->step_total == 0)
+      return 0;
+
+   return (int)((state->step_current * 100) / (state->step_total));
+}
+
+/**
+ * file_archive_extract_file:
+ * @archive_path                : filename path to archive.
+ * @valid_exts                  : valid extensions for the file.
+ * @extraction_directory        : the directory to extract temporary
+ *                                file to.
+ *
+ * Extract file from archive. If no file inside the archive is
+ * specified, the first file found will be used.
+ *
+ * Returns : true (1) on success, otherwise false (0).
+ **/
+bool file_archive_extract_file(
+      const char *archive_path,
+      const char *valid_exts,
+      const char *extraction_directory,
+      char *out_path, size_t len)
+{
+   struct archive_extract_userdata userdata;
+   bool ret                                 = true;
+   struct string_list *list                 = string_split(valid_exts, "|");
+
+   userdata.archive_path[0]                 = '\0';
+   userdata.current_file_path[0]            = '\0';
+   userdata.first_extracted_file_path       = NULL;
+   userdata.extraction_directory            = extraction_directory;
+   userdata.ext                             = list;
+   userdata.list                            = NULL;
+   userdata.found_file                      = false;
+   userdata.list_only                       = false;
+   userdata.crc                             = 0;
+   userdata.transfer                        = NULL;
+   userdata.dec                             = NULL;
+
+   if (!list)
+   {
+      ret = false;
+      goto end;
+   }
+
+   if (!file_archive_walk(archive_path, valid_exts,
+            file_archive_extract_cb, &userdata))
+   {
+      /* Parsing file archive failed. */
+      ret = false;
+      goto end;
+   }
+
+   if (!userdata.found_file)
+   {
+      /* Didn't find any file that matched valid extensions
+       * for libretro implementation. */
+      ret = false;
+      goto end;
+   }
+
+   if (!string_is_empty(userdata.first_extracted_file_path))
+      strlcpy(out_path, userdata.first_extracted_file_path, len);
+
+end:
+   if (userdata.first_extracted_file_path)
+      free(userdata.first_extracted_file_path);
+   if (list)
+      string_list_free(list);
+   return ret;
+}
+
+/* Warning: 'list' must zero initialised before
+ * calling this function, otherwise memory leaks/
+ * undefined behaviour will occur */
+bool file_archive_get_file_list_noalloc(struct string_list *list,
+      const char *path,
+      const char *valid_exts)
+{
+   struct archive_extract_userdata userdata;
+
+   if (!list || !string_list_initialize(list))
+      return false;
+
+   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
+   userdata.current_file_path[0]            = '\0';
+   userdata.first_extracted_file_path       = NULL;
+   userdata.extraction_directory            = NULL;
+   userdata.ext                             = NULL;
+   userdata.list                            = list;
+   userdata.found_file                      = false;
+   userdata.list_only                       = true;
+   userdata.crc                             = 0;
+   userdata.transfer                        = NULL;
+   userdata.dec                             = NULL;
+
+   if (!file_archive_walk(path, valid_exts,
+            file_archive_get_file_list_cb, &userdata))
+      return false;
+   return true;
+}
+
+/**
+ * file_archive_get_file_list:
+ * @path                        : filename path of archive
+ *
+ * Returns: string listing of files from archive on success, otherwise NULL.
+ **/
+struct string_list *file_archive_get_file_list(const char *path,
+      const char *valid_exts)
+{
+   struct archive_extract_userdata userdata;
+
+   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
+   userdata.current_file_path[0]            = '\0';
+   userdata.first_extracted_file_path       = NULL;
+   userdata.extraction_directory            = NULL;
+   userdata.ext                             = NULL;
+   userdata.list                            = string_list_new();
+   userdata.found_file                      = false;
+   userdata.list_only                       = true;
+   userdata.crc                             = 0;
+   userdata.transfer                        = NULL;
+   userdata.dec                             = NULL;
+
+   if (!userdata.list)
+      return NULL;
+   if (!file_archive_walk(path, valid_exts,
+         file_archive_get_file_list_cb, &userdata))
+   {
+      string_list_free(userdata.list);
+      return NULL;
+   }
+   return userdata.list;
+}
+
+bool file_archive_perform_mode(const char *path, const char *valid_exts,
+      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
+      uint32_t crc32, struct archive_extract_userdata *userdata)
+{
+   file_archive_file_handle_t handle;
+   int ret;
+
+   if (!userdata->transfer || !userdata->transfer->backend)
+      return false;
+
+   handle.data          = NULL;
+   handle.real_checksum = 0;
+
+   if (!userdata->transfer->backend->stream_decompress_data_to_file_init(
+            userdata->transfer->context, &handle, cdata, cmode, csize, size))
+      return false;
+
+   do
+   {
+      ret = userdata->transfer->backend->stream_decompress_data_to_file_iterate(
+               userdata->transfer->context, &handle);
+   }while (ret == 0);
+
+   if (ret == -1 || !file_archive_decompress_data_to_file(
+            userdata->transfer, &handle, path,
+            size, crc32))
+      return false;
+
+   return true;
+}
+
+/**
+ * file_archive_filename_split:
+ * @str              : filename to turn into a string list
+ *
+ * Creates a new string list based on filename @path, delimited by a hash (#).
+ *
+ * Returns: new string list if successful, otherwise NULL.
+ */
+static struct string_list *file_archive_filename_split(const char *path)
+{
+   union string_list_elem_attr attr;
+   struct string_list *list = string_list_new();
+   const char *delim        = path_get_archive_delim(path);
+
+   attr.i = 0;
+
+   if (delim)
+   {
+      /* add archive path to list first */
+      if (!string_list_append_n(list, path, (unsigned)(delim - path), attr))
+         goto error;
+
+      /* now add the path within the archive */
+      delim++;
+
+      if (*delim)
+      {
+         if (!string_list_append(list, delim, attr))
+            goto error;
+      }
+   }
+   else
+      if (!string_list_append(list, path, attr))
+         goto error;
+
+   return list;
+
+error:
+   string_list_free(list);
+   return NULL;
+}
+
+/* Generic compressed file loader.
+ * Extracts to buf, unless optional_filename != 0
+ * Then extracts to optional_filename and leaves buf alone.
+ */
+int file_archive_compressed_read(
+      const char * path, void **buf,
+      const char* optional_filename, int64_t *length)
+{
+   const struct 
+      file_archive_file_backend *backend = NULL;
+   struct string_list *str_list          = NULL;
+
+   /* Safety check.
+    * If optional_filename and optional_filename
+    * exists, we simply return 0,
+    * hoping that optional_filename is the
+    * same as requested.
+    */
+   if (optional_filename && path_is_valid(optional_filename))
+   {
+      *length = 0;
+      return 1;
+   }
+
+   str_list       = file_archive_filename_split(path);
+   /* We assure that there is something after the '#' symbol.
+    *
+    * This error condition happens for example, when
+    * path = /path/to/file.7z, or
+    * path = /path/to/file.7z#
+    */
+   if (str_list->size <= 1)
+   {
+      /* could not extract string and substring. */
+      string_list_free(str_list);
+      *length = 0;
+      return 0;
+   }
+
+   backend = file_archive_get_file_backend(str_list->elems[0].data);
+   *length = backend->compressed_file_read(str_list->elems[0].data,
+         str_list->elems[1].data, buf, optional_filename);
+
+   string_list_free(str_list);
+
+   if (*length != -1)
+      return 1;
+
+   return 0;
+}
+
+const struct file_archive_file_backend *file_archive_get_zlib_file_backend(void)
+{
+#ifdef HAVE_ZLIB
+   return &zlib_backend;
+#else
+   return NULL;
+#endif
+}
+
+const struct file_archive_file_backend *file_archive_get_7z_file_backend(void)
+{
+#ifdef HAVE_7ZIP
+   return &sevenzip_backend;
+#else
+   return NULL;
+#endif
+}
+
+const struct file_archive_file_backend* file_archive_get_file_backend(const char *path)
+{
+#if defined(HAVE_7ZIP) || defined(HAVE_ZLIB)
+   char newpath[PATH_MAX_LENGTH];
+   const char *file_ext          = NULL;
+   char *last                    = NULL;
+
+   strlcpy(newpath, path, sizeof(newpath));
+
+   if ((last = (char*)path_get_archive_delim(newpath)))
+      *last  = '\0';
+
+   file_ext  = path_get_extension(newpath);
+
+#ifdef HAVE_7ZIP
+   if (string_is_equal_noncase(file_ext, "7z"))
+      return &sevenzip_backend;
+#endif
+
+#ifdef HAVE_ZLIB
+   if (     string_is_equal_noncase(file_ext, "zip")
+         || string_is_equal_noncase(file_ext, "apk")
+      )
+      return &zlib_backend;
+#endif
+#endif
+
+   return NULL;
+}
+
+/**
+ * file_archive_get_file_crc32:
+ * @path                         : filename path of archive
+ *
+ * Returns: CRC32 of the specified file in the archive, otherwise 0.
+ * If no path within the archive is specified, the first
+ * file found inside is used.
+ **/
+uint32_t file_archive_get_file_crc32(const char *path)
+{
+   file_archive_transfer_t state;
+   struct archive_extract_userdata userdata        = {0};
+   bool returnerr                                  = false;
+   const char *archive_path                        = NULL;
+   bool contains_compressed = path_contains_compressed_file(path);
+
+   if (contains_compressed)
+   {
+      archive_path = path_get_archive_delim(path);
+
+      /* move pointer right after the delimiter to give us the path */
+      if (archive_path)
+         archive_path += 1;
+   }
+
+   state.type              = ARCHIVE_TRANSFER_INIT;
+   state.archive_file      = NULL;
+#ifdef HAVE_MMAP
+   state.archive_mmap_fd   = 0;
+   state.archive_mmap_data = NULL;
+#endif
+   state.archive_size      = 0;
+   state.context           = NULL;
+   state.step_total        = 0;
+   state.step_current      = 0;
+   state.backend           = NULL;
+
+   /* Initialize and open archive first.
+      Sets next state type to ITERATE. */
+   file_archive_parse_file_iterate(&state,
+            &returnerr, path, NULL, NULL,
+            &userdata);
+
+   for (;;)
+   {
+      /* Now find the first file in the archive. */
+      if (state.type == ARCHIVE_TRANSFER_ITERATE)
+         file_archive_parse_file_iterate(&state,
+                  &returnerr, path, NULL, NULL,
+                  &userdata);
+
+      /* If no path specified within archive, stop after
+       * finding the first file.
+       */
+      if (!contains_compressed)
+         break;
+
+      /* Stop when the right file in the archive is found. */
+      if (archive_path)
+      {
+         if (string_is_equal(userdata.current_file_path, archive_path))
+            break;
+      }
+      else
+         break;
+   }
+
+   file_archive_parse_file_iterate_stop(&state);
+
+   return userdata.crc;
+}
diff --git a/deps/libretro-common/file/archive_file_7z.c b/deps/libretro-common/file/archive_file_7z.c
new file mode 100644 (file)
index 0000000..c0aa7ad
--- /dev/null
@@ -0,0 +1,526 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (archive_file_sevenzip.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+
+#include <boolean.h>
+#include <file/archive_file.h>
+#include <streams/file_stream.h>
+#include <retro_miscellaneous.h>
+#include <encodings/utf.h>
+#include <encodings/crc32.h>
+#include <string/stdstring.h>
+#include <lists/string_list.h>
+#include <file/file_path.h>
+#include <compat/strl.h>
+#include <7zip/7z.h>
+#include <7zip/7zCrc.h>
+#include <7zip/7zFile.h>
+
+#define SEVENZIP_MAGIC "7z\xBC\xAF\x27\x1C"
+#define SEVENZIP_MAGIC_LEN 6
+#define SEVENZIP_LOOKTOREAD_BUF_SIZE (1 << 14)
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+#endif
+
+struct sevenzip_context_t
+{
+   uint8_t *output;
+   CFileInStream archiveStream;
+   CLookToRead2 lookStream;
+   ISzAlloc allocImp;
+   ISzAlloc allocTempImp;
+   CSzArEx db;
+   size_t temp_size;
+   uint32_t parse_index;
+   uint32_t decompress_index;
+   uint32_t packIndex;
+   uint32_t   block_index;
+};
+
+static void *sevenzip_stream_alloc_impl(ISzAllocPtr p, size_t size)
+{
+   if (size == 0)
+      return 0;
+   return malloc(size);
+}
+
+static void sevenzip_stream_free_impl(ISzAllocPtr p, void *address)
+{
+   (void)p;
+
+   if (address)
+      free(address);
+}
+
+static void *sevenzip_stream_alloc_tmp_impl(ISzAllocPtr p, size_t size)
+{
+   (void)p;
+   if (size == 0)
+      return 0;
+   return malloc(size);
+}
+
+static void* sevenzip_stream_new(void)
+{
+   struct sevenzip_context_t *sevenzip_context =
+         (struct sevenzip_context_t*)calloc(1, sizeof(struct sevenzip_context_t));
+
+   /* These are the allocation routines - currently using
+    * the non-standard 7zip choices. */
+   sevenzip_context->allocImp.Alloc     = sevenzip_stream_alloc_impl;
+   sevenzip_context->allocImp.Free      = sevenzip_stream_free_impl;
+   sevenzip_context->allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;
+   sevenzip_context->allocTempImp.Free  = sevenzip_stream_free_impl;
+   sevenzip_context->block_index        = 0xFFFFFFFF;
+   sevenzip_context->output             = NULL;
+
+   sevenzip_context->lookStream.bufSize = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);
+   sevenzip_context->lookStream.buf     = (Byte*)malloc(sevenzip_context->lookStream.bufSize);
+
+   if (!sevenzip_context->lookStream.buf)
+      sevenzip_context->lookStream.bufSize = 0;
+
+   return sevenzip_context;
+}
+
+static void sevenzip_parse_file_free(void *context)
+{
+   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;
+
+   if (!sevenzip_context)
+      return;
+
+   if (sevenzip_context->output)
+   {
+      IAlloc_Free(&sevenzip_context->allocImp, sevenzip_context->output);
+      sevenzip_context->output       = NULL;
+   }
+
+   SzArEx_Free(&sevenzip_context->db, &sevenzip_context->allocImp);
+   File_Close(&sevenzip_context->archiveStream.file);
+
+   if (sevenzip_context->lookStream.buf)
+      free(sevenzip_context->lookStream.buf);
+
+   free(sevenzip_context);
+}
+
+/* Extract the relative path (needle) from a 7z archive
+ * (path) and allocate a buf for it to write it in.
+ * If optional_outfile is set, extract to that instead
+ * and don't allocate buffer.
+ */
+static int64_t sevenzip_file_read(
+      const char *path,
+      const char *needle, void **buf,
+      const char *optional_outfile)
+{
+   CFileInStream archiveStream;
+   CLookToRead2 lookStream;
+   ISzAlloc allocImp;
+   ISzAlloc allocTempImp;
+   CSzArEx db;
+   uint8_t *output      = 0;
+   int64_t outsize      = -1;
+
+   /*These are the allocation routines.
+    * Currently using the non-standard 7zip choices. */
+   allocImp.Alloc       = sevenzip_stream_alloc_impl;
+   allocImp.Free        = sevenzip_stream_free_impl;
+   allocTempImp.Alloc   = sevenzip_stream_alloc_tmp_impl;
+   allocTempImp.Free    = sevenzip_stream_free_impl;
+
+   lookStream.bufSize   = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);
+   lookStream.buf       = (Byte*)malloc(lookStream.bufSize);
+
+   if (!lookStream.buf)
+      lookStream.bufSize = 0;
+
+#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)
+   if (!string_is_empty(path))
+   {
+      wchar_t *pathW = utf8_to_utf16_string_alloc(path);
+
+      if (pathW)
+      {
+         /* Could not open 7zip archive? */
+         if (InFile_OpenW(&archiveStream.file, pathW))
+         {
+            free(pathW);
+            return -1;
+         }
+
+         free(pathW);
+      }
+   }
+#else
+   /* Could not open 7zip archive? */
+   if (InFile_Open(&archiveStream.file, path))
+      return -1;
+#endif
+
+   FileInStream_CreateVTable(&archiveStream);
+   LookToRead2_CreateVTable(&lookStream, false);
+   lookStream.realStream = &archiveStream.vt;
+   LookToRead2_Init(&lookStream);
+   CrcGenerateTable();
+
+   memset(&db, 0, sizeof(db));
+
+   SzArEx_Init(&db);
+
+   if (SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp) == SZ_OK)
+   {
+      uint32_t i;
+      bool file_found      = false;
+      uint16_t *temp       = NULL;
+      size_t temp_size     = 0;
+      uint32_t block_index   = 0xFFFFFFFF;
+      SRes res             = SZ_OK;
+
+      for (i = 0; i < db.NumFiles; i++)
+      {
+         size_t len;
+         char infile[PATH_MAX_LENGTH];
+         size_t offset                = 0;
+         size_t outSizeProcessed      = 0;
+
+         /* We skip over everything which is not a directory.
+          * FIXME: Why continue then if IsDir is true?*/
+         if (SzArEx_IsDir(&db, i))
+            continue;
+
+         len = SzArEx_GetFileNameUtf16(&db, i, NULL);
+
+         if (len > temp_size)
+         {
+            if (temp)
+               free(temp);
+            temp_size = len;
+            temp = (uint16_t *)malloc(temp_size * sizeof(temp[0]));
+
+            if (temp == 0)
+            {
+               res = SZ_ERROR_MEM;
+               break;
+            }
+         }
+
+         SzArEx_GetFileNameUtf16(&db, i, temp);
+         res       = SZ_ERROR_FAIL;
+         infile[0] = '\0';
+
+         if (temp)
+            res = utf16_to_char_string(temp, infile, sizeof(infile))
+               ? SZ_OK : SZ_ERROR_FAIL;
+
+         if (string_is_equal(infile, needle))
+         {
+            size_t output_size   = 0;
+
+            /* C LZMA SDK does not support chunked extraction - see here:
+             * sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/
+             * */
+            file_found = true;
+            res = SzArEx_Extract(&db, &lookStream.vt, i, &block_index,
+                  &output, &output_size, &offset, &outSizeProcessed,
+                  &allocImp, &allocTempImp);
+
+            if (res != SZ_OK)
+               break; /* This goes to the error section. */
+
+            outsize = (int64_t)outSizeProcessed;
+
+            if (optional_outfile)
+            {
+               const void *ptr = (const void*)(output + offset);
+
+               if (!filestream_write_file(optional_outfile, ptr, outsize))
+               {
+                  res        = SZ_OK;
+                  file_found = true;
+                  outsize    = -1;
+               }
+            }
+            else
+            {
+               /*We could either use the 7Zip allocated buffer,
+                * or create our own and use it.
+                * We would however need to realloc anyways, because RetroArch
+                * expects a \0 at the end, therefore we allocate new,
+                * copy and free the old one. */
+               *buf = malloc((size_t)(outsize + 1));
+               ((char*)(*buf))[outsize] = '\0';
+               memcpy(*buf,output + offset,outsize);
+            }
+            break;
+         }
+      }
+
+      if (temp)
+         free(temp);
+      IAlloc_Free(&allocImp, output);
+
+      if (!(file_found && res == SZ_OK))
+      {
+         /* Error handling
+          *
+          * Failed to open compressed file inside 7zip archive.
+          */
+
+         outsize    = -1;
+      }
+   }
+
+   SzArEx_Free(&db, &allocImp);
+   File_Close(&archiveStream.file);
+
+   if (lookStream.buf)
+      free(lookStream.buf);
+
+   return outsize;
+}
+
+static bool sevenzip_stream_decompress_data_to_file_init(
+      void *context, file_archive_file_handle_t *handle,
+      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
+{
+   struct sevenzip_context_t *sevenzip_context =
+         (struct sevenzip_context_t*)context;
+
+   if (!sevenzip_context)
+      return false;
+
+   sevenzip_context->decompress_index = (uint32_t)(size_t)cdata;
+
+   return true;
+}
+
+static int sevenzip_stream_decompress_data_to_file_iterate(
+      void *context, file_archive_file_handle_t *handle)
+{
+   struct sevenzip_context_t *sevenzip_context =
+         (struct sevenzip_context_t*)context;
+
+   SRes res                = SZ_ERROR_FAIL;
+   size_t output_size      = 0;
+   size_t offset           = 0;
+   size_t outSizeProcessed = 0;
+
+   res = SzArEx_Extract(&sevenzip_context->db,
+         &sevenzip_context->lookStream.vt, sevenzip_context->decompress_index,
+         &sevenzip_context->block_index, &sevenzip_context->output,
+         &output_size, &offset, &outSizeProcessed,
+         &sevenzip_context->allocImp, &sevenzip_context->allocTempImp);
+
+   if (res != SZ_OK)
+      return 0;
+
+   if (handle)
+      handle->data = sevenzip_context->output + offset;
+
+   return 1;
+}
+
+static int sevenzip_parse_file_init(file_archive_transfer_t *state,
+      const char *file)
+{
+   uint8_t magic_buf[SEVENZIP_MAGIC_LEN];
+   struct sevenzip_context_t *sevenzip_context = NULL;
+
+   if (state->archive_size < SEVENZIP_MAGIC_LEN)
+      goto error;
+
+   filestream_seek(state->archive_file, 0, SEEK_SET);
+   if (filestream_read(state->archive_file, magic_buf, SEVENZIP_MAGIC_LEN) != SEVENZIP_MAGIC_LEN)
+      goto error;
+
+   if (string_is_not_equal_fast(magic_buf, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN))
+      goto error;
+
+   sevenzip_context = (struct sevenzip_context_t*)sevenzip_stream_new();
+   state->context = sevenzip_context;
+
+#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)
+   if (!string_is_empty(file))
+   {
+      wchar_t *fileW = utf8_to_utf16_string_alloc(file);
+
+      if (fileW)
+      {
+         /* could not open 7zip archive? */
+         if (InFile_OpenW(&sevenzip_context->archiveStream.file, fileW))
+         {
+            free(fileW);
+            goto error;
+         }
+
+         free(fileW);
+      }
+   }
+#else
+   /* could not open 7zip archive? */
+   if (InFile_Open(&sevenzip_context->archiveStream.file, file))
+      goto error;
+#endif
+
+   FileInStream_CreateVTable(&sevenzip_context->archiveStream);
+   LookToRead2_CreateVTable(&sevenzip_context->lookStream, false);
+   sevenzip_context->lookStream.realStream = &sevenzip_context->archiveStream.vt;
+   LookToRead2_Init(&sevenzip_context->lookStream);
+   CrcGenerateTable();
+   SzArEx_Init(&sevenzip_context->db);
+
+   if (SzArEx_Open(&sevenzip_context->db, &sevenzip_context->lookStream.vt,
+         &sevenzip_context->allocImp, &sevenzip_context->allocTempImp) != SZ_OK)
+      goto error;
+
+   state->step_total = sevenzip_context->db.NumFiles;
+
+   return 0;
+
+error:
+   if (sevenzip_context)
+      sevenzip_parse_file_free(sevenzip_context);
+   return -1;
+}
+
+static int sevenzip_parse_file_iterate_step_internal(
+      struct sevenzip_context_t *sevenzip_context, char *filename,
+      const uint8_t **cdata, unsigned *cmode,
+      uint32_t *size, uint32_t *csize, uint32_t *checksum,
+      unsigned *payback, struct archive_extract_userdata *userdata)
+{
+   if (sevenzip_context->parse_index < sevenzip_context->db.NumFiles)
+   {
+      size_t len = SzArEx_GetFileNameUtf16(&sevenzip_context->db,
+            sevenzip_context->parse_index, NULL);
+      uint64_t compressed_size = 0;
+
+      if (sevenzip_context->packIndex < sevenzip_context->db.db.NumPackStreams)
+      {
+         compressed_size = sevenzip_context->db.db.PackPositions[sevenzip_context->packIndex + 1] -
+               sevenzip_context->db.db.PackPositions[sevenzip_context->packIndex];
+
+         sevenzip_context->packIndex++;
+      }
+
+      if (len < PATH_MAX_LENGTH &&
+          !SzArEx_IsDir(&sevenzip_context->db, sevenzip_context->parse_index))
+      {
+         char infile[PATH_MAX_LENGTH];
+         SRes res                     = SZ_ERROR_FAIL;
+         uint16_t *temp               = (uint16_t*)malloc(len * sizeof(uint16_t));
+
+         if (!temp)
+            return -1;
+
+         infile[0] = '\0';
+
+         SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->parse_index,
+               temp);
+
+         if (temp)
+         {
+            res  = utf16_to_char_string(temp, infile, sizeof(infile))
+               ? SZ_OK : SZ_ERROR_FAIL;
+            free(temp);
+         }
+
+         if (res != SZ_OK)
+            return -1;
+
+         strlcpy(filename, infile, PATH_MAX_LENGTH);
+
+         *cmode    = 0; /* unused for 7zip */
+         *checksum = sevenzip_context->db.CRCs.Vals[sevenzip_context->parse_index];
+         *size     = (uint32_t)SzArEx_GetFileSize(&sevenzip_context->db, sevenzip_context->parse_index);
+         *csize    = (uint32_t)compressed_size;
+
+         *cdata    = (uint8_t *)(size_t)sevenzip_context->parse_index;
+      }
+   }
+   else
+      return 0;
+
+   *payback = 1;
+
+   return 1;
+}
+
+static int sevenzip_parse_file_iterate_step(void *context,
+      const char *valid_exts,
+      struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)
+{
+   const uint8_t *cdata = NULL;
+   uint32_t checksum    = 0;
+   uint32_t size        = 0;
+   uint32_t csize       = 0;
+   unsigned cmode       = 0;
+   unsigned payload     = 0;
+   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;
+   int ret;
+
+   userdata->current_file_path[0] = '\0';
+
+   ret = sevenzip_parse_file_iterate_step_internal(sevenzip_context,
+         userdata->current_file_path,
+         &cdata, &cmode, &size, &csize,
+         &checksum, &payload, userdata);
+
+   if (ret != 1)
+      return ret;
+
+   userdata->crc                 = checksum;
+
+   if (file_cb && !file_cb(userdata->current_file_path, valid_exts,
+            cdata, cmode,
+            csize, size, checksum, userdata))
+      return 0;
+
+   sevenzip_context->parse_index += payload;
+
+   return 1;
+}
+
+static uint32_t sevenzip_stream_crc32_calculate(uint32_t crc,
+      const uint8_t *data, size_t length)
+{
+   return encoding_crc32(crc, data, length);
+}
+
+const struct file_archive_file_backend sevenzip_backend = {
+   sevenzip_parse_file_init,
+   sevenzip_parse_file_iterate_step,
+   sevenzip_parse_file_free,
+   sevenzip_stream_decompress_data_to_file_init,
+   sevenzip_stream_decompress_data_to_file_iterate,
+   sevenzip_stream_crc32_calculate,
+   sevenzip_file_read,
+   "7z"
+};
diff --git a/deps/libretro-common/file/archive_file_zlib.c b/deps/libretro-common/file/archive_file_zlib.c
new file mode 100644 (file)
index 0000000..f9cd64b
--- /dev/null
@@ -0,0 +1,563 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (archive_file_zlib.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <file/archive_file.h>
+#include <streams/file_stream.h>
+#include <retro_inline.h>
+#include <retro_miscellaneous.h>
+#include <encodings/crc32.h>
+
+#include <zlib.h>
+
+#ifndef CENTRAL_FILE_HEADER_SIGNATURE
+#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
+#endif
+
+#ifndef END_OF_CENTRAL_DIR_SIGNATURE
+#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
+#endif
+
+#define _READ_CHUNK_SIZE   (128*1024)   /* Read 128KiB compressed chunks */
+
+enum file_archive_compression_mode
+{
+   ZIP_MODE_STORED   = 0,
+   ZIP_MODE_DEFLATED = 8
+};
+
+typedef struct
+{
+   struct file_archive_transfer *state;
+   uint8_t *directory;
+   uint8_t *directory_entry;
+   uint8_t *directory_end;
+   uint64_t fdoffset;
+   uint32_t boffset, csize, usize;
+   unsigned cmode;
+   z_stream *zstream;
+   uint8_t *tmpbuf;
+   uint8_t *decompressed_data;
+} zip_context_t;
+
+static INLINE uint32_t read_le(const uint8_t *data, unsigned size)
+{
+   unsigned i;
+   uint32_t val = 0;
+
+   size *= 8;
+   for (i = 0; i < size; i += 8)
+      val |= (uint32_t)*data++ << i;
+
+   return val;
+}
+
+static void zip_context_free_stream(
+      zip_context_t *zip_context, bool keep_decompressed)
+{
+   if (zip_context->zstream)
+   {
+      inflateEnd(zip_context->zstream);
+      free(zip_context->zstream);
+      zip_context->fdoffset = 0;
+      zip_context->csize = 0;
+      zip_context->usize = 0;
+      zip_context->zstream = NULL;
+   }
+   if (zip_context->tmpbuf)
+   {
+      free(zip_context->tmpbuf);
+      zip_context->tmpbuf = NULL;
+   }
+   if (zip_context->decompressed_data && !keep_decompressed)
+   {
+      free(zip_context->decompressed_data);
+      zip_context->decompressed_data = NULL;
+   }
+}
+
+static bool zlib_stream_decompress_data_to_file_init(
+      void *context, file_archive_file_handle_t *handle,
+      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
+{
+   zip_context_t *zip_context = (zip_context_t *)context;
+   struct file_archive_transfer *state = zip_context->state;
+   uint8_t local_header_buf[4];
+   uint8_t *local_header;
+   uint32_t offsetNL, offsetEL;
+   int64_t offsetData;
+
+   /* free previous data and stream if left unfinished */
+   zip_context_free_stream(zip_context, false);
+
+   /* seek past most of the local directory header */
+#ifdef HAVE_MMAP
+   if (state->archive_mmap_data)
+   {
+      local_header = state->archive_mmap_data + (size_t)cdata + 26;
+   }
+   else
+#endif
+   {
+      filestream_seek(state->archive_file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);
+      if (filestream_read(state->archive_file, local_header_buf, 4) != 4)
+         goto error;
+      local_header = local_header_buf;
+   }
+
+   offsetNL = read_le(local_header,     2); /* file name length */
+   offsetEL = read_le(local_header + 2, 2); /* extra field length */
+   offsetData = (int64_t)(size_t)cdata + 26 + 4 + offsetNL + offsetEL;
+
+   zip_context->fdoffset = offsetData;
+   zip_context->usize = size;
+   zip_context->csize = csize;
+   zip_context->boffset = 0;
+   zip_context->cmode = cmode;
+   zip_context->decompressed_data = (uint8_t*)malloc(size);
+   zip_context->zstream = NULL;
+   zip_context->tmpbuf = NULL;
+
+   if (cmode == ZIP_MODE_DEFLATED)
+   {
+      /* Initialize the zlib inflate machinery */
+      zip_context->zstream = (z_stream*)malloc(sizeof(z_stream));
+      zip_context->tmpbuf = malloc(_READ_CHUNK_SIZE);
+
+      zip_context->zstream->next_in   = NULL;
+      zip_context->zstream->avail_in  = 0;
+      zip_context->zstream->total_in  = 0;
+      zip_context->zstream->next_out  = zip_context->decompressed_data;
+      zip_context->zstream->avail_out = size;
+      zip_context->zstream->total_out = 0;
+
+      zip_context->zstream->zalloc    = NULL;
+      zip_context->zstream->zfree     = NULL;
+      zip_context->zstream->opaque    = NULL;
+
+      if (inflateInit2(zip_context->zstream, -MAX_WBITS) != Z_OK) {
+         free(zip_context->zstream);
+         zip_context->zstream = NULL;
+         goto error;
+      }
+   }
+
+   return true;
+
+error:
+   zip_context_free_stream(zip_context, false);
+   return false;
+}
+
+static int zlib_stream_decompress_data_to_file_iterate(
+      void *context, file_archive_file_handle_t *handle)
+{
+   zip_context_t *zip_context = (zip_context_t *)context;
+   struct file_archive_transfer *state = zip_context->state;
+   int64_t rd;
+
+   if (zip_context->cmode == ZIP_MODE_STORED)
+   {
+      #ifdef HAVE_MMAP
+      if (zip_context->state->archive_mmap_data)
+      {
+         /* Simply copy the data to the output buffer */
+         memcpy(zip_context->decompressed_data,
+                zip_context->state->archive_mmap_data + (size_t)zip_context->fdoffset,
+                zip_context->usize);
+      }
+      else
+      #endif
+      {
+         /* Read the entire file to memory */
+         filestream_seek(state->archive_file, zip_context->fdoffset, RETRO_VFS_SEEK_POSITION_START);
+         if (filestream_read(state->archive_file,
+                             zip_context->decompressed_data,
+                             zip_context->usize) < 0)
+            return -1;
+      }
+
+      handle->data = zip_context->decompressed_data;
+      return 1;
+   }
+   else if (zip_context->cmode == ZIP_MODE_DEFLATED)
+   {
+      int to_read = MIN(zip_context->csize - zip_context->boffset, _READ_CHUNK_SIZE);
+      uint8_t *dptr;
+      if (!zip_context->zstream)
+      {
+         /* file was uncompressed or decompression finished before */
+         return 1;
+      }
+
+      #ifdef HAVE_MMAP
+      if (state->archive_mmap_data)
+      {
+         /* Decompress from the mapped file */
+         dptr = state->archive_mmap_data + (size_t)zip_context->fdoffset + zip_context->boffset;
+         rd = to_read;
+      }
+      else
+      #endif
+      {
+         /* Read some compressed data from file to the temp buffer */
+         filestream_seek(state->archive_file, zip_context->fdoffset + zip_context->boffset,
+                         RETRO_VFS_SEEK_POSITION_START);
+         rd = filestream_read(state->archive_file, zip_context->tmpbuf, to_read);
+         if (rd < 0)
+            return -1;
+         dptr = zip_context->tmpbuf;
+      }
+
+      zip_context->boffset           += rd;
+      zip_context->zstream->next_in   = dptr;
+      zip_context->zstream->avail_in  = (uInt)rd;
+
+      if (inflate(zip_context->zstream, 0) < 0)
+         return -1;
+
+      if (zip_context->boffset >= zip_context->csize)
+      {
+         inflateEnd(zip_context->zstream);
+         free(zip_context->zstream);
+         zip_context->zstream = NULL;
+
+         handle->data = zip_context->decompressed_data;
+         return 1;
+      }
+
+      return 0;   /* still more data to process */
+   }
+
+   /* No idea what kind of compression this is */
+   return -1;
+}
+
+static uint32_t zlib_stream_crc32_calculate(uint32_t crc,
+      const uint8_t *data, size_t length)
+{
+   return encoding_crc32(crc, data, length);
+}
+
+static bool zip_file_decompressed_handle(
+      file_archive_transfer_t *transfer,
+      file_archive_file_handle_t* handle,
+      const uint8_t *cdata, unsigned cmode, uint32_t csize,
+      uint32_t size, uint32_t crc32)
+{
+   int ret   = 0;
+
+   transfer->backend = &zlib_backend;
+
+   if (!transfer->backend->stream_decompress_data_to_file_init(
+            transfer->context, handle, cdata, cmode, csize, size))
+      return false;
+
+   do
+   {
+      ret = transfer->backend->stream_decompress_data_to_file_iterate(
+            transfer->context, handle);
+      if (ret < 0)
+         return false;
+   }while (ret == 0);
+
+   return true;
+}
+
+typedef struct
+{
+   char *opt_file;
+   char *needle;
+   void **buf;
+   size_t size;
+   bool found;
+} decomp_state_t;
+
+/* Extract the relative path (needle) from a
+ * ZIP archive (path) and allocate a buffer for it to write it in.
+ *
+ * optional_outfile if not NULL will be used to extract the file to.
+ * buf will be 0 then.
+ */
+
+static int zip_file_decompressed(
+      const char *name, const char *valid_exts,
+      const uint8_t *cdata, unsigned cmode,
+      uint32_t csize, uint32_t size,
+      uint32_t crc32, struct archive_extract_userdata *userdata)
+{
+   decomp_state_t* decomp_state = (decomp_state_t*)userdata->cb_data;
+   char last_char = name[strlen(name) - 1];
+   /* Ignore directories. */
+   if (last_char == '/' || last_char == '\\')
+      return 1;
+
+   if (strstr(name, decomp_state->needle))
+   {
+      file_archive_file_handle_t handle = {0};
+
+      if (zip_file_decompressed_handle(userdata->transfer,
+               &handle, cdata, cmode, csize, size, crc32))
+      {
+         if (decomp_state->opt_file != 0)
+         {
+            /* Called in case core has need_fullpath enabled. */
+            bool success = filestream_write_file(decomp_state->opt_file, handle.data, size);
+
+            /* Note: Do not free handle.data here - this
+             * will be done when stream is deinitialised */
+            handle.data = NULL;
+
+            decomp_state->size = 0;
+
+            if (!success)
+               return -1;
+         }
+         else
+         {
+            /* Called in case core has need_fullpath disabled.
+             * Will move decompressed content directly into
+             * RetroArch's ROM buffer. */
+            zip_context_t *zip_context = (zip_context_t *)userdata->transfer->context;
+
+            decomp_state->size = 0;
+            *decomp_state->buf             = handle.data;
+            decomp_state->size             = size;
+            /* We keep the data, prevent its deallocation during free */
+            zip_context->decompressed_data = NULL;
+            handle.data = NULL;
+         }
+      }
+
+      decomp_state->found = true;
+   }
+
+   return 1;
+}
+
+static int64_t zip_file_read(
+      const char *path,
+      const char *needle, void **buf,
+      const char *optional_outfile)
+{
+   file_archive_transfer_t state            = {0};
+   decomp_state_t decomp                    = {0};
+   struct archive_extract_userdata userdata = {0};
+   bool returnerr                           = true;
+   int ret                                  = 0;
+
+   if (needle)
+      decomp.needle          = strdup(needle);
+   if (optional_outfile)
+      decomp.opt_file        = strdup(optional_outfile);
+
+   state.type                = ARCHIVE_TRANSFER_INIT;
+   userdata.transfer         = &state;
+   userdata.cb_data          = &decomp;
+   decomp.buf                = buf;
+
+   do
+   {
+      ret = file_archive_parse_file_iterate(&state, &returnerr, path,
+            "", zip_file_decompressed, &userdata);
+      if (!returnerr)
+         break;
+   }while (ret == 0 && !decomp.found);
+
+   file_archive_parse_file_iterate_stop(&state);
+
+   if (decomp.opt_file)
+      free(decomp.opt_file);
+   if (decomp.needle)
+      free(decomp.needle);
+
+   if (!decomp.found)
+      return -1;
+
+   return (int64_t)decomp.size;
+}
+
+static int zip_parse_file_init(file_archive_transfer_t *state,
+      const char *file)
+{
+   uint8_t footer_buf[1024];
+   uint8_t *footer = footer_buf;
+   int64_t read_pos = state->archive_size;
+   int64_t read_block = MIN(read_pos, (ssize_t)sizeof(footer_buf));
+   int64_t directory_size, directory_offset;
+   zip_context_t *zip_context = NULL;
+
+   /* Minimal ZIP file size is 22 bytes */
+   if (read_block < 22)
+      return -1;
+
+   /* Find the end of central directory record by scanning
+    * the file from the end towards the beginning.
+    */
+   for (;;)
+   {
+      if (--footer < footer_buf)
+      {
+         if (read_pos <= 0)
+            return -1; /* reached beginning of file */
+
+         /* Read 21 bytes of overlaps except on the first block. */
+         if (read_pos == state->archive_size)
+            read_pos = read_pos - read_block;
+         else
+            read_pos = MAX(read_pos - read_block + 21, 0);
+
+         /* Seek to read_pos and read read_block bytes. */
+         filestream_seek(state->archive_file, read_pos, RETRO_VFS_SEEK_POSITION_START);
+         if (filestream_read(state->archive_file, footer_buf, read_block) != read_block)
+            return -1;
+
+         footer = footer_buf + read_block - 22;
+      }
+      if (read_le(footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)
+      {
+         unsigned comment_len = read_le(footer + 20, 2);
+         if (read_pos + (footer - footer_buf) + 22 + comment_len == state->archive_size)
+            break; /* found it! */
+      }
+   }
+
+   /* Read directory info and do basic sanity checks. */
+   directory_size   = read_le(footer + 12, 4);
+   directory_offset = read_le(footer + 16, 4);
+   if (directory_size > state->archive_size
+         || directory_offset > state->archive_size)
+      return -1;
+
+   /* This is a ZIP file, allocate one block of memory for both the
+    * context and the entire directory, then read the directory.
+    */
+   zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);
+   zip_context->state             = state;
+   zip_context->directory         = (uint8_t*)(zip_context + 1);
+   zip_context->directory_entry   = zip_context->directory;
+   zip_context->directory_end     = zip_context->directory + (size_t)directory_size;
+   zip_context->zstream           = NULL;
+   zip_context->tmpbuf            = NULL;
+   zip_context->decompressed_data = NULL;
+
+   filestream_seek(state->archive_file, directory_offset, RETRO_VFS_SEEK_POSITION_START);
+   if (filestream_read(state->archive_file, zip_context->directory, directory_size) != directory_size)
+   {
+      free(zip_context);
+      return -1;
+   }
+
+   state->context = zip_context;
+   state->step_total = read_le(footer + 10, 2); /* total entries */;
+
+   return 0;
+}
+
+static int zip_parse_file_iterate_step_internal(
+      zip_context_t * zip_context, char *filename,
+      const uint8_t **cdata,
+      unsigned *cmode, uint32_t *size, uint32_t *csize,
+      uint32_t *checksum, unsigned *payback)
+{
+   uint8_t *entry = zip_context->directory_entry;
+   uint32_t signature, namelength, extralength, commentlength, offset;
+
+   if (entry < zip_context->directory || entry >= zip_context->directory_end)
+      return 0;
+
+   signature = read_le(zip_context->directory_entry + 0, 4);
+
+   if (signature != CENTRAL_FILE_HEADER_SIGNATURE)
+      return 0;
+
+   *cmode         = read_le(zip_context->directory_entry + 10, 2); /* compression mode, 0 = store, 8 = deflate */
+   *checksum      = read_le(zip_context->directory_entry + 16, 4); /* CRC32 */
+   *csize         = read_le(zip_context->directory_entry + 20, 4); /* compressed size */
+   *size          = read_le(zip_context->directory_entry + 24, 4); /* uncompressed size */
+
+   namelength     = read_le(zip_context->directory_entry + 28, 2); /* file name length */
+   extralength    = read_le(zip_context->directory_entry + 30, 2); /* extra field length */
+   commentlength  = read_le(zip_context->directory_entry + 32, 2); /* file comment length */
+
+   if (namelength >= PATH_MAX_LENGTH)
+      return -1;
+
+   memcpy(filename, zip_context->directory_entry + 46, namelength); /* file name */
+   filename[namelength] = '\0';
+
+   offset   = read_le(zip_context->directory_entry + 42, 4); /* relative offset of local file header */
+
+   *cdata   = (uint8_t*)(size_t)offset; /* store file offset in data pointer */
+
+   *payback = 46 + namelength + extralength + commentlength;
+
+   return 1;
+}
+
+static int zip_parse_file_iterate_step(void *context,
+      const char *valid_exts, struct archive_extract_userdata *userdata,
+      file_archive_file_cb file_cb)
+{
+   zip_context_t *zip_context = (zip_context_t *)context;
+   const uint8_t *cdata           = NULL;
+   uint32_t checksum              = 0;
+   uint32_t size                  = 0;
+   uint32_t csize                 = 0;
+   unsigned cmode                 = 0;
+   unsigned payload               = 0;
+   int ret                        = zip_parse_file_iterate_step_internal(zip_context,
+         userdata->current_file_path, &cdata, &cmode, &size, &csize, &checksum, &payload);
+
+   if (ret != 1)
+      return ret;
+
+   userdata->crc = checksum;
+
+   if (file_cb && !file_cb(userdata->current_file_path, valid_exts, cdata, cmode,
+            csize, size, checksum, userdata))
+      return 0;
+
+   zip_context->directory_entry += payload;
+
+   return 1;
+}
+
+static void zip_parse_file_free(void *context)
+{
+   zip_context_t *zip_context = (zip_context_t *)context;
+   zip_context_free_stream(zip_context, false);
+   free(zip_context);
+}
+
+const struct file_archive_file_backend zlib_backend = {
+   zip_parse_file_init,
+   zip_parse_file_iterate_step,
+   zip_parse_file_free,
+   zlib_stream_decompress_data_to_file_init,
+   zlib_stream_decompress_data_to_file_iterate,
+   zlib_stream_crc32_calculate,
+   zip_file_read,
+   "zlib"
+};
diff --git a/deps/libretro-common/file/config_file.c b/deps/libretro-common/file/config_file.c
new file mode 100644 (file)
index 0000000..0e77083
--- /dev/null
@@ -0,0 +1,1522 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (config_file.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <retro_miscellaneous.h>
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+#include <compat/fopen_utf8.h>
+#include <compat/msvc.h>
+#include <file/config_file.h>
+#include <file/file_path.h>
+#include <string/stdstring.h>
+#include <streams/file_stream.h>
+#include <array/rhmap.h>
+
+#define MAX_INCLUDE_DEPTH 16
+
+struct config_include_list
+{
+   char *path;
+   struct config_include_list *next;
+};
+
+/* Forward declaration */
+static bool config_file_parse_line(config_file_t *conf,
+      struct config_entry_list *list, char *line, config_file_cb_t *cb);
+
+static int config_file_sort_compare_func(struct config_entry_list *a,
+      struct config_entry_list *b)
+{
+   if (a && b)
+   {
+      if (a->key)
+      {
+         if (b->key)
+            return strcasecmp(a->key, b->key);
+         return 1;
+      }
+      else if (b->key)
+         return -1;
+   }
+
+   return 0;
+}
+
+/* https://stackoverflow.com/questions/7685/merge-sort-a-linked-list */
+static struct config_entry_list* config_file_merge_sort_linked_list(
+         struct config_entry_list *list, int (*compare)(
+         struct config_entry_list *one,struct config_entry_list *two))
+{
+   struct config_entry_list
+         *right  = list,
+         *temp   = list,
+         *last   = list,
+         *result = 0,
+         *next   = 0,
+         *tail   = 0;
+
+   /* Trivial case. */
+   if (!list || !list->next)
+      return list;
+
+   /* Find halfway through the list (by running two pointers,
+    * one at twice the speed of the other). */
+   while (temp && temp->next)
+   {
+      last     = right;
+      right    = right->next;
+      temp     = temp->next->next;
+   }
+
+   /* Break the list in two. (prev pointers are broken here,
+    * but we fix later) */
+   last->next  = 0;
+
+   /* Recurse on the two smaller lists: */
+   list        = config_file_merge_sort_linked_list(list, compare);
+   right       = config_file_merge_sort_linked_list(right, compare);
+
+   /* Merge: */
+   while (list || right)
+   {
+      /* Take from empty lists, or compare: */
+      if (!right)
+      {
+         next  = list;
+         list  = list->next;
+      }
+      else if (!list)
+      {
+         next  = right;
+         right = right->next;
+      }
+      else if (compare(list, right) < 0)
+      {
+         next  = list;
+         list  = list->next;
+      }
+      else
+      {
+         next  = right;
+         right = right->next;
+      }
+
+      if (!result)
+         result     = next;
+      else
+         tail->next = next;
+
+      tail          = next;
+   }
+
+   return result;
+}
+
+/**
+ * config_file_strip_comment:
+ *
+ * Searches input string for a comment ('#') entry
+ * > If first character is '#', then entire line is
+ *   a comment and may correspond to a directive
+ *   (command action - e.g. include sub-config file).
+ *   In this case, 'str' is set to NUL and the comment
+ *   itself (everything after the '#' character) is
+ *   returned
+ * > If a '#' character is found inside a string literal
+ *   value, then it does not correspond to a comment and
+ *   is ignored. In this case, 'str' is left untouched
+ *   and NULL is returned
+ * > If a '#' character is found anywhere else, then the
+ *   comment text is a suffix of the input string and
+ *   has no programmatic value. In this case, the comment
+ *   is removed from the end of 'str' and NULL is returned
+ **/
+static char *config_file_strip_comment(char *str)
+{
+   /* Search for a comment (#) character */
+   char *comment = strchr(str, '#');
+
+   if (comment)
+   {
+      char *literal_start = NULL;
+
+      /* Check whether entire line is a comment
+       * > First character == '#' */
+      if (str == comment)
+      {
+         /* Set 'str' to NUL and return comment
+          * for processing at a higher level */
+         *str = '\0';
+         return ++comment;
+      }
+
+      /* Comment character occurs at an offset:
+       * Search for the start of a string literal value */
+      literal_start = strchr(str, '\"');
+
+      /* Check whether string literal start occurs
+       * *before* the comment character */
+      if (literal_start && (literal_start < comment))
+      {
+         /* Search for the end of the string literal
+          * value */
+         char *literal_end = strchr(literal_start + 1, '\"');
+
+         /* Check whether string literal end occurs
+          * *after* the comment character
+          * > If this is the case, ignore the comment
+          * > Leave 'str' untouched and return NULL */
+         if (literal_end && (literal_end > comment))
+            return NULL;
+      }
+
+      /* If we reach this point, then a comment
+       * exists outside of a string literal
+       * > Trim the entire comment from the end
+       *   of 'str' */
+      *comment = '\0';
+   }
+
+   return NULL;
+}
+
+static char *config_file_extract_value(char *line)
+{
+   char *dst = NULL;
+   while (ISSPACE((int)*line))
+      line++;
+
+   /* Note: From this point on, an empty value
+    * string is valid - and in this case, strldup("", sizeof(""))
+    * will be returned (see Note 2)
+    * > If we instead return NULL, the the entry
+    *   is ignored completely - which means we cannot
+    *   track *changes* in entry value */
+
+   /* If first character is ("), we have a full string
+    * literal */
+   if (*line == '"')
+   {
+      size_t idx  = 0;
+      char *value = NULL;
+      /* Skip to next character */
+      line++;
+
+      /* If this a ("), then value string is empty */
+      if (*line != '"')
+      {
+         /* Find the next (") character */
+         while (line[idx] && (line[idx] != '\"'))
+            idx++;
+
+         line[idx] = '\0';
+         if ((value = line) && *value)
+            return strdup(value);
+      }
+   }
+   /* This is not a string literal - just read
+    * until the next space is found
+    * > Note: Skip this if line is empty */
+   else if (*line != '\0')
+   {
+      size_t idx  = 0;
+      char *value = NULL;
+      /* Find next space character */
+      while (line[idx] && isgraph((int)line[idx]))
+         idx++;
+
+      line[idx] = '\0';
+      if ((value = line) && *value)
+         return strdup(value);
+   }
+
+   /* Note 2: This is an unrolled strldup call 
+    * to avoid an unnecessary dependency -
+    * call is strldup("", sizeof(""))
+    **/
+   dst = (char*)malloc(sizeof(char) * 2);
+   strlcpy(dst, "", 1);
+   return dst;
+}
+
+/* Move semantics? */
+static void config_file_add_child_list(config_file_t *parent,
+      config_file_t *child)
+{
+   struct config_entry_list *list = child->entries;
+   bool merge_hash_map            = false;
+
+   if (parent->entries)
+   {
+      struct config_entry_list *head = parent->entries;
+      while (head->next)
+         head = head->next;
+
+      /* set list readonly */
+      while (list)
+      {
+         list->readonly = true;
+         list           = list->next;
+      }
+      head->next        = child->entries;
+
+      merge_hash_map    = true;
+   }
+   else
+   {
+      /* set list readonly */
+      while (list)
+      {
+         list->readonly = true;
+         list           = list->next;
+      }
+      parent->entries   = child->entries;
+   }
+
+   /* Rebase tail. */
+   if (parent->entries)
+   {
+      struct config_entry_list *head =
+         (struct config_entry_list*)parent->entries;
+
+      while (head->next)
+         head = head->next;
+      parent->tail = head;
+   }
+   else
+      parent->tail = NULL;
+
+   /* Update hash map */
+   if (merge_hash_map)
+   {
+      size_t i;
+      size_t cap;
+
+      /* We are merging two lists - if any child entry
+       * (key) is not present in the parent list, add it
+       * to the parent hash map */
+      for (i = 0, cap = RHMAP_CAP(child->entries_map); i != cap; i++)
+      {
+         uint32_t child_hash   = RHMAP_KEY(child->entries_map, i);
+         const char *child_key = RHMAP_KEY_STR(child->entries_map, i);
+
+         if (child_hash &&
+             child_key &&
+             !RHMAP_HAS_FULL(parent->entries_map, child_hash, child_key))
+         {
+            struct config_entry_list *entry = child->entries_map[i];
+
+            if (entry)
+               RHMAP_SET_FULL(parent->entries_map, child_hash, child_key, entry);
+         }
+      }
+
+      /* Child entries map is no longer required,
+       * so free it now */
+      RHMAP_FREE(child->entries_map);
+   }
+   else
+   {
+      /* If parent list was originally empty,
+       * take map from child list */
+      RHMAP_FREE(parent->entries_map);
+      parent->entries_map = child->entries_map;
+      child->entries_map  = NULL;
+   }
+
+   child->entries = NULL;
+}
+
+static void config_file_get_realpath(char *s, size_t len,
+      char *path, const char *config_path)
+{
+#ifdef _WIN32
+   if (!string_is_empty(config_path))
+      fill_pathname_resolve_relative(s, config_path,
+            path, len);
+#else
+#if !defined(__PSL1GHT__) && !defined(__PS3__)
+   if (*path == '~')
+   {
+      const char *home = getenv("HOME");
+      if (home)
+      {
+         strlcpy(s, home,     len);
+         strlcat(s, path + 1, len);
+      }
+      else
+         strlcpy(s, path + 1, len);
+   }
+   else
+#endif
+      if (!string_is_empty(config_path))
+         fill_pathname_resolve_relative(s, config_path, path, len);
+#endif
+}
+
+static void config_file_add_sub_conf(config_file_t *conf, char *path,
+      char *real_path, size_t len, config_file_cb_t *cb)
+{
+   struct config_include_list *head = conf->includes;
+   struct config_include_list *node = (struct config_include_list*)
+      malloc(sizeof(*node));
+
+   if (node)
+   {
+      node->next        = NULL;
+      /* Add include list */
+      node->path        = strdup(path);
+
+      if (head)
+      {
+         while (head->next)
+            head        = head->next;
+
+         head->next     = node;
+      }
+      else
+         conf->includes = node;
+   }
+
+   config_file_get_realpath(real_path, len, path,
+         conf->path);
+}
+
+void config_file_add_reference(config_file_t *conf, char *path)
+{
+   /* It is expected that the conf has it's path already set */
+   char short_path[PATH_MAX_LENGTH];
+   if (!conf->references)
+      conf->references = path_linked_list_new();
+   fill_pathname_abbreviated_or_relative(short_path, conf->path, path, sizeof(short_path));
+   path_linked_list_add_path(conf->references, short_path);
+}
+
+static int config_file_load_internal(
+      struct config_file *conf,
+      const char *path, unsigned depth, config_file_cb_t *cb)
+{
+   RFILE         *file = NULL;
+   char      *new_path = strdup(path);
+   if (!new_path)
+      return 1;
+
+   conf->path          = new_path;
+   conf->include_depth = depth;
+
+   if (!(file = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
+   {
+      free(conf->path);
+      return 1;
+   }
+
+   while (!filestream_eof(file))
+   {
+      char *line                     = NULL;
+      struct config_entry_list *list = (struct config_entry_list*)
+         malloc(sizeof(*list));
+
+      if (!list)
+      {
+         filestream_close(file);
+         return -1;
+      }
+
+      list->readonly  = false;
+      list->key       = NULL;
+      list->value     = NULL;
+      list->next      = NULL;
+
+      line            = filestream_getline(file);
+
+      if (!line)
+      {
+         free(list);
+         continue;
+      }
+
+      if ( 
+              !string_is_empty(line) 
+            && config_file_parse_line(conf, list, line, cb))
+      {
+         if (conf->entries)
+            conf->tail->next = list;
+         else
+            conf->entries    = list;
+
+         conf->tail = list;
+
+         if (list->key)
+         {
+            /* Only add entry to the map if an entry
+             * with the specified value does not
+             * already exist */
+            uint32_t hash = rhmap_hash_string(list->key);
+
+            if (!RHMAP_HAS_FULL(conf->entries_map, hash, list->key))
+            {
+               RHMAP_SET_FULL(conf->entries_map, hash, list->key, list);
+
+               if (cb && list->value)
+                  cb->config_file_new_entry_cb(list->key, list->value);
+            }
+         }
+      }
+
+      free(line);
+
+      if (list != conf->tail)
+         free(list);
+   }
+
+   filestream_close(file);
+
+   return 0;
+}
+
+static bool config_file_parse_line(config_file_t *conf,
+      struct config_entry_list *list, char *line, config_file_cb_t *cb)
+{
+   size_t cur_size       = 32;
+   size_t idx            = 0;
+   char *key             = NULL;
+   char *key_tmp         = NULL;
+   /* Remove any comment text */
+   char *comment         = config_file_strip_comment(line);
+
+   /* Check whether entire line is a comment */
+   if (comment)
+   {
+      char *path               = NULL;
+      bool include_found       = string_starts_with_size(comment,
+            "include ",
+            STRLEN_CONST("include "));
+      bool reference_found     = string_starts_with_size(comment,
+            "reference ",
+            STRLEN_CONST("reference "));
+
+      /* All comments except those starting with the include or 
+       * reference directive are ignored */
+      if (!include_found && !reference_found)
+         return false;
+
+      /* Starting a line with an 'include' directive
+       * appends a sub-config file */
+      if (include_found)
+      {
+         config_file_t sub_conf;
+         char real_path[PATH_MAX_LENGTH];
+         char *include_line = comment + STRLEN_CONST("include ");
+
+         if (string_is_empty(include_line))
+            return false;
+
+         if (!(path = config_file_extract_value(include_line)))
+            return false;
+
+         if (     string_is_empty(path)
+               || conf->include_depth >= MAX_INCLUDE_DEPTH)
+         {
+            free(path);
+            return false;
+         }
+
+         config_file_add_sub_conf(conf, path,
+            real_path, sizeof(real_path), cb);
+
+         config_file_initialize(&sub_conf);
+
+         switch (config_file_load_internal(&sub_conf, real_path,
+            conf->include_depth + 1, cb))
+         {
+            case 0:
+               /* Pilfer internal list. */
+               config_file_add_child_list(conf, &sub_conf);
+               /* fall-through to deinitialize */
+            case -1:
+               config_file_deinitialize(&sub_conf);
+               break;
+            case 1:
+            default:
+               break;
+         }
+      }
+
+      /* Starting a line with an 'reference' directive
+       * sets the reference path */
+      if (reference_found)
+      {
+         char *reference_line = comment + STRLEN_CONST("reference ");
+
+         if (string_is_empty(reference_line))
+            return false;
+
+         if (!(path = config_file_extract_value(reference_line)))
+            return false;
+
+         config_file_add_reference(conf, path);
+
+         if (!path)
+            return false;
+      }
+
+      free(path);
+      return true;
+   }
+
+   /* Skip to first non-space character */
+   while (ISSPACE((int)*line))
+      line++;
+
+   /* Allocate storage for key */
+   if (!(key = (char*)malloc(cur_size + 1)))
+      return false;
+
+   /* Copy line contents into key until we
+    * reach the next space character */
+   while (isgraph((int)*line))
+   {
+      /* If current key storage is too small,
+       * double its size */
+      if (idx == cur_size)
+      {
+         cur_size *= 2;
+         if (!(key_tmp   = (char*)realloc(key, cur_size + 1)))
+         {
+            free(key);
+            return false;
+         }
+
+         key     = key_tmp;
+      }
+
+      key[idx++] = *line++;
+   }
+   key[idx]      = '\0';
+
+   /* Add key and value entries to list */
+   list->key     = key;
+
+   /* An entry without a value is invalid */
+   while (ISSPACE((int)*line))
+      line++;
+
+   /* If we don't have an equal sign here,
+    * we've got an invalid string. */
+   if (*line != '=')
+   {
+      list->value = NULL;
+      goto error;
+   }
+
+   line++;
+
+   if (!(list->value   = config_file_extract_value(line)))
+      goto error;
+
+   return true;
+
+error:
+   list->key   = NULL;
+   free(key);
+   return false;
+}
+
+static int config_file_from_string_internal(
+      struct config_file *conf,
+      char *from_string,
+      const char *path)
+{
+   char *lines                    = from_string;
+   char *save_ptr                 = NULL;
+   char *line                     = NULL;
+
+   if (!string_is_empty(path))
+      conf->path                  = strdup(path);
+   if (string_is_empty(lines))
+      return 0;
+
+   /* Get first line of config file */
+   line = strtok_r(lines, "\n", &save_ptr);
+
+   while (line)
+   {
+      struct config_entry_list *list = (struct config_entry_list*)
+            malloc(sizeof(*list));
+
+      if (!list)
+         return -1;
+
+      list->readonly  = false;
+      list->key       = NULL;
+      list->value     = NULL;
+      list->next      = NULL;
+
+      /* Parse current line */
+      if (
+              !string_is_empty(line)
+            && config_file_parse_line(conf, list, line, NULL))
+      {
+         if (conf->entries)
+            conf->tail->next = list;
+         else
+            conf->entries    = list;
+
+         conf->tail          = list;
+
+         if (list->key)
+         {
+            /* Only add entry to the map if an entry
+             * with the specified value does not
+             * already exist */
+            uint32_t hash = rhmap_hash_string(list->key);
+            if (!RHMAP_HAS_FULL(conf->entries_map, hash, list->key))
+               RHMAP_SET_FULL(conf->entries_map, hash, list->key, list);
+         }
+      }
+
+      if (list != conf->tail)
+         free(list);
+
+      /* Get next line of config file */
+      line = strtok_r(NULL, "\n", &save_ptr);
+   }
+   
+   return 0;
+}
+
+
+bool config_file_deinitialize(config_file_t *conf)
+{
+   struct config_include_list *inc_tmp = NULL;
+   struct config_entry_list *tmp       = NULL;
+
+   if (!conf)
+      return false;
+
+   tmp = conf->entries;
+   while (tmp)
+   {
+      struct config_entry_list *hold = NULL;
+      if (tmp->key)
+         free(tmp->key);
+      if (tmp->value)
+         free(tmp->value);
+
+      tmp->value = NULL;
+      tmp->key   = NULL;
+
+      hold       = tmp;
+      tmp        = tmp->next;
+
+      if (hold)
+         free(hold);
+   }
+
+   inc_tmp = (struct config_include_list*)conf->includes;
+   while (inc_tmp)
+   {
+      struct config_include_list *hold = NULL;
+      if (inc_tmp->path)
+         free(inc_tmp->path);
+      hold    = (struct config_include_list*)inc_tmp;
+      inc_tmp = inc_tmp->next;
+      if (hold)
+         free(hold);
+   }
+
+   path_linked_list_free(conf->references);
+
+   if (conf->path)
+      free(conf->path);
+
+   RHMAP_FREE(conf->entries_map);
+
+   return true;
+}
+
+/**
+ * config_file_free:
+ *
+ * Frees config file.
+ **/
+void config_file_free(config_file_t *conf)
+{
+   if (config_file_deinitialize(conf))
+      free(conf);
+}
+
+/**
+ * config_append_file:
+ *
+ * Loads a new config, and appends its data to @conf.
+ * The key-value pairs of the new config file takes priority over the old.
+ **/
+bool config_append_file(config_file_t *conf, const char *path)
+{
+   size_t i, cap;
+   config_file_t *new_conf = config_file_new_from_path_to_string(path);
+
+   if (!new_conf)
+      return false;
+
+   /* Update hash map */
+   for (i = 0, cap = RHMAP_CAP(new_conf->entries_map); i != cap; i++)
+   {
+      uint32_t new_hash   = RHMAP_KEY(new_conf->entries_map, i);
+      const char *new_key = RHMAP_KEY_STR(new_conf->entries_map, i);
+
+      if (new_hash && new_key)
+      {
+         struct config_entry_list *entry = new_conf->entries_map[i];
+
+         if (entry)
+            RHMAP_SET_FULL(conf->entries_map, new_hash, new_key, entry);
+      }
+   }
+
+   if (new_conf->tail)
+   {
+      new_conf->tail->next = conf->entries;
+      conf->entries        = new_conf->entries; /* Pilfer. */
+      new_conf->entries    = NULL;
+   }
+
+   config_file_free(new_conf);
+   return true;
+}
+
+/**
+ * config_file_new_from_string:
+ *
+ * Load a config file from a string.
+ *
+ * NOTE: This will modify @from_string.
+ * Pass a copy of source string if original
+ * contents must be preserved
+ **/
+config_file_t *config_file_new_from_string(char *from_string,
+      const char *path)
+{
+   struct config_file *conf      = config_file_new_alloc();
+   if (     conf 
+         && config_file_from_string_internal(
+            conf, from_string, path) != -1)
+      return conf;
+   if (conf)
+      config_file_free(conf);
+   return NULL;
+}
+
+config_file_t *config_file_new_from_path_to_string(const char *path)
+{
+   if (path_is_valid(path))
+   {
+          uint8_t *ret_buf                 = NULL;
+      int64_t length                   = 0;
+      if (filestream_read_file(path, (void**)&ret_buf, &length))
+      {
+         config_file_t *conf           = NULL;
+         /* Note: 'ret_buf' is not used outside this
+          * function - we do not care that it will be
+          * modified by config_file_new_from_string() */
+         if (length >= 0)
+            conf = config_file_new_from_string((char*)ret_buf, path);
+
+         if ((void*)ret_buf)
+            free((void*)ret_buf);
+
+         return conf;
+      }
+   }
+
+   return NULL;
+}
+
+/**
+ * config_file_new_with_callback:
+ *
+ * Loads a config file.
+ * If @path is NULL, will create an empty config file.
+ * Includes cb callbacks  to run custom code during config file processing.
+ *
+ * @return Returns NULL if file doesn't exist.
+ **/
+config_file_t *config_file_new_with_callback(
+      const char *path, config_file_cb_t *cb)
+{
+   int ret                  = 0;
+   struct config_file *conf = config_file_new_alloc();
+   if (!path || !*path)
+      return conf;
+   if ((ret = config_file_load_internal(conf, path, 0, cb)) == -1)
+   {
+      config_file_free(conf);
+      return NULL;
+   }
+   else if (ret == 1)
+   {
+      free(conf);
+      return NULL;
+   }
+   return conf;
+}
+
+/**
+ * config_file_new:
+ *
+ * Loads a config file.
+ * If @path is NULL, will create an empty config file.
+ *
+ * @return Returns NULL if file doesn't exist.
+ **/
+config_file_t *config_file_new(const char *path)
+{
+   int ret                  = 0;
+   struct config_file *conf = config_file_new_alloc();
+   if (!path || !*path)
+      return conf;
+   if ((ret = config_file_load_internal(conf, path, 0, NULL)) == -1)
+   {
+      config_file_free(conf);
+      return NULL;
+   }
+   else if (ret == 1)
+   {
+      free(conf);
+      return NULL;
+   }
+   return conf;
+}
+
+/**
+ * config_file_initialize:
+ *
+ * Leaf function.
+ **/
+void config_file_initialize(struct config_file *conf)
+{
+   if (!conf)
+      return;
+
+   conf->path                     = NULL;
+   conf->entries_map              = NULL;
+   conf->entries                  = NULL;
+   conf->tail                     = NULL;
+   conf->last                     = NULL;
+   conf->references               = NULL;
+   conf->includes                 = NULL;
+   conf->include_depth            = 0;
+   conf->guaranteed_no_duplicates = false;
+   conf->modified                 = false;
+}
+
+config_file_t *config_file_new_alloc(void)
+{
+   struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));
+   if (!conf)
+      return NULL;
+   config_file_initialize(conf);
+   return conf;
+}
+
+/**
+ * config_get_entry_internal:
+ *
+ * Leaf function.
+ **/
+static struct config_entry_list *config_get_entry_internal(
+      const config_file_t *conf,
+      const char *key, struct config_entry_list **prev)
+{
+   struct config_entry_list *entry = RHMAP_GET_STR(conf->entries_map, key);
+
+   if (entry)
+      return entry;
+
+   if (prev)
+   {
+      struct config_entry_list *previous = *prev;
+      for (entry = conf->entries; entry; entry = entry->next)
+         previous = entry;
+
+      *prev = previous;
+   }
+
+   return NULL;
+}
+
+struct config_entry_list *config_get_entry(
+      const config_file_t *conf, const char *key)
+{
+   return RHMAP_GET_STR(conf->entries_map, key);
+}
+
+/**
+ * config_get_double:
+ *
+ * Extracts a double from config file.
+ *
+ * @return true if found, otherwise false.
+ **/
+bool config_get_double(config_file_t *conf, const char *key, double *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+
+   if (!entry)
+      return false;
+
+   *in = strtod(entry->value, NULL);
+   return true;
+}
+
+/**
+ * config_get_float:
+ *
+ * Extracts a float from config file.
+ *
+ * @return true if found, otherwise false.
+ **/
+bool config_get_float(config_file_t *conf, const char *key, float *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+
+   if (!entry)
+      return false;
+
+   /* strtof() is C99/POSIX. Just use the more portable kind. */
+   *in = (float)strtod(entry->value, NULL);
+   return true;
+}
+
+bool config_get_int(config_file_t *conf, const char *key, int *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+   errno = 0;
+
+   if (entry)
+   {
+      int val = (int)strtol(entry->value, NULL, 0);
+
+      if (errno == 0)
+      {
+         *in = val;
+         return true;
+      }
+   }
+
+   return false;
+}
+
+bool config_get_size_t(config_file_t *conf, const char *key, size_t *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+   errno = 0;
+
+   if (entry)
+   {
+      size_t val = 0;
+      if (sscanf(entry->value, "%" PRI_SIZET, &val) == 1)
+      {
+         *in = val;
+         return true;
+      }
+   }
+
+   return false;
+}
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
+bool config_get_uint64(config_file_t *conf, const char *key, uint64_t *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+   errno = 0;
+
+   if (entry)
+   {
+      uint64_t val = strtoull(entry->value, NULL, 0);
+
+      if (errno == 0)
+      {
+         *in = val;
+         return true;
+      }
+   }
+   return false;
+}
+#endif
+
+bool config_get_uint(config_file_t *conf, const char *key, unsigned *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+   errno = 0;
+
+   if (entry)
+   {
+      unsigned val = (unsigned)strtoul(entry->value, NULL, 0);
+
+      if (errno == 0)
+      {
+         *in = val;
+         return true;
+      }
+   }
+
+   return false;
+}
+
+bool config_get_hex(config_file_t *conf, const char *key, unsigned *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+   errno = 0;
+
+   if (entry)
+   {
+      unsigned val = (unsigned)strtoul(entry->value, NULL, 16);
+
+      if (errno == 0)
+      {
+         *in = val;
+         return true;
+      }
+   }
+
+   return false;
+}
+
+/**
+ * config_get_char:
+ *
+ * Extracts a single char from config file.
+ * If value consists of several chars, this is an error.
+ *
+ * @return true if found, otherwise false.
+ **/
+bool config_get_char(config_file_t *conf, const char *key, char *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+
+   if (entry)
+   {
+      if (entry->value[0] && entry->value[1])
+         return false;
+
+      *in = *entry->value;
+      return true;
+   }
+
+   return false;
+}
+
+/**
+ * config_get_string:
+ *
+ * Extracts an allocated string in *in. This must be free()-d if
+ * this function succeeds.
+ *
+ * @return true if found, otherwise false.
+ **/
+bool config_get_string(config_file_t *conf, const char *key, char **str)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+
+   if (!entry || !entry->value)
+      return false;
+
+   *str = strdup(entry->value);
+   return true;
+}
+
+/**
+  * config_get_config_path:
+  *
+  * Extracts a string to a preallocated buffer.
+  * Avoid memory allocation.
+  **/
+bool config_get_config_path(config_file_t *conf, char *s, size_t len)
+{
+   if (conf)
+      return strlcpy(s, conf->path, len);
+   return false;
+}
+
+bool config_get_array(config_file_t *conf, const char *key,
+      char *buf, size_t size)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+   if (entry)
+      return strlcpy(buf, entry->value, size) < size;
+   return false;
+}
+
+bool config_get_path(config_file_t *conf, const char *key,
+      char *buf, size_t size)
+{
+#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)
+   if (config_get_array(conf, key, buf, size))
+      return true;
+#else
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+   if (entry)
+   {
+      fill_pathname_expand_special(buf, entry->value, size);
+      return true;
+   }
+#endif
+   return false;
+}
+
+/**
+ * config_get_bool:
+ * 
+ * Extracts a boolean from config.
+ * Valid boolean true are "true" and "1". Valid false are "false" and "0".
+ * Other values will be treated as an error.
+ *
+ * @return true if preconditions are true, otherwise false.
+ **/
+bool config_get_bool(config_file_t *conf, const char *key, bool *in)
+{
+   const struct config_entry_list *entry = config_get_entry(conf, key);
+
+   if (!entry)
+      return false;
+
+   if      (
+         (
+            entry->value[0] == '1'
+         && entry->value[1] == '\0'
+         )
+         || string_is_equal(entry->value, "true")
+         )
+      *in = true;
+   else if (
+         (
+            entry->value[0] == '0'
+         && entry->value[1] == '\0'
+         )
+         || string_is_equal(entry->value, "false")
+         )
+      *in = false;
+   else
+      return false;
+
+   return true;
+}
+
+void config_set_string(config_file_t *conf, const char *key, const char *val)
+{
+   struct config_entry_list *last  = NULL;
+   struct config_entry_list *entry = NULL;
+
+   if (!conf || !key || !val)
+      return;
+
+   last                            = conf->entries;
+
+   if (conf->guaranteed_no_duplicates)
+   {
+      if (conf->last)
+         last                      = conf->last;
+   }
+   else
+   {
+      if ((entry = config_get_entry_internal(conf, key, &last)))
+      {
+         /* An entry corresponding to 'key' already exists
+          * > Check whether value is currently set */
+         if (entry->value)
+         {
+            /* Do nothing if value is unchanged */
+            if (string_is_equal(entry->value, val))
+               return;
+
+            /* Value is to be updated
+             * > Free existing */
+            free(entry->value);
+         }
+
+         /* Update value
+          * > Note that once a value is set, it
+          *   is no longer considered 'read only' */
+         entry->value    = strdup(val);
+         entry->readonly = false;
+         conf->modified  = true;
+         return;
+      }
+   }
+
+   /* Entry corresponding to 'key' does not exist
+    * > Create new entry */
+   if (!(entry = (struct config_entry_list*)malloc(sizeof(*entry))))
+      return;
+
+   entry->readonly  = false;
+   entry->key       = strdup(key);
+   entry->value     = strdup(val);
+   entry->next      = NULL;
+   conf->modified   = true;
+
+   if (last)
+      last->next    = entry;
+   else
+      conf->entries = entry;
+
+   conf->last       = entry;
+
+   RHMAP_SET_STR(conf->entries_map, entry->key, entry);
+}
+
+void config_unset(config_file_t *conf, const char *key)
+{
+   struct config_entry_list *last  = NULL;
+   struct config_entry_list *entry = NULL;
+
+   if (!conf || !key)
+      return;
+
+   last  = conf->entries;
+
+   if (!(entry = config_get_entry_internal(conf, key, &last)))
+      return;
+
+   (void)RHMAP_DEL_STR(conf->entries_map, entry->key);
+
+   if (entry->key)
+      free(entry->key);
+
+   if (entry->value)
+      free(entry->value);
+
+   entry->key     = NULL;
+   entry->value   = NULL;
+   conf->modified = true;
+}
+
+void config_set_path(config_file_t *conf, const char *entry, const char *val)
+{
+#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)
+   config_set_string(conf, entry, val);
+#else
+   char buf[PATH_MAX_LENGTH];
+   fill_pathname_abbreviate_special(buf, val, sizeof(buf));
+   config_set_string(conf, entry, buf);
+#endif
+}
+
+void config_set_double(config_file_t *conf, const char *key, double val)
+{
+   char buf[320];
+#ifdef __cplusplus
+   snprintf(buf, sizeof(buf), "%f", (float)val);
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
+   snprintf(buf, sizeof(buf), "%lf", val);
+#else
+   snprintf(buf, sizeof(buf), "%f", (float)val);
+#endif
+   config_set_string(conf, key, buf);
+}
+
+void config_set_float(config_file_t *conf, const char *key, float val)
+{
+   char buf[64];
+   snprintf(buf, sizeof(buf), "%f", val);
+   config_set_string(conf, key, buf);
+}
+
+void config_set_int(config_file_t *conf, const char *key, int val)
+{
+   char buf[16];
+   snprintf(buf, sizeof(buf), "%d", val);
+   config_set_string(conf, key, buf);
+}
+
+void config_set_uint(config_file_t *conf, const char *key, unsigned int val)
+{
+   char buf[16];
+   snprintf(buf, sizeof(buf), "%u", val);
+   config_set_string(conf, key, buf);
+}
+
+void config_set_hex(config_file_t *conf, const char *key, unsigned val)
+{
+   char buf[16];
+   snprintf(buf, sizeof(buf), "%x", val);
+   config_set_string(conf, key, buf);
+}
+
+void config_set_uint64(config_file_t *conf, const char *key, uint64_t val)
+{
+   char buf[32];
+   snprintf(buf, sizeof(buf), "%" PRIu64, val);
+   config_set_string(conf, key, buf);
+}
+
+void config_set_char(config_file_t *conf, const char *key, char val)
+{
+   char buf[2];
+   snprintf(buf, sizeof(buf), "%c", val);
+   config_set_string(conf, key, buf);
+}
+
+/**
+ * config_set_bool:
+
+ * TODO/FIXME - could be turned into a trivial macro or removed
+ **/
+void config_set_bool(config_file_t *conf, const char *key, bool val)
+{
+   config_set_string(conf, key, val ? "true" : "false");
+}
+
+/**
+ * config_file_write:
+ *
+ * Write the current config to a file.
+ **/
+bool config_file_write(config_file_t *conf, const char *path, bool sort)
+{
+   if (!conf)
+      return false;
+
+   if (!conf->modified)
+      return true;
+
+   if (!string_is_empty(path))
+   {
+      void* buf  = NULL;
+      FILE *file = (FILE*)fopen_utf8(path, "wb");
+      if (!file)
+         return false;
+
+      buf        = calloc(1, 0x4000);
+      setvbuf(file, (char*)buf, _IOFBF, 0x4000);
+
+      config_file_dump(conf, file, sort);
+
+      if (file != stdout)
+         fclose(file);
+      if (buf)
+         free(buf);
+
+      /* Only update modified flag if config file
+       * is actually written to disk */
+      conf->modified = false;
+   }
+   else
+      config_file_dump(conf, stdout, sort);
+
+   return true;
+}
+
+/**
+ * config_file_dump:
+ *
+ * Dump the current config to an already opened file.
+ * Does not close the file.
+ **/
+void config_file_dump(config_file_t *conf, FILE *file, bool sort)
+{
+   struct config_entry_list       *list = NULL;
+   struct config_include_list *includes = conf->includes;
+   struct path_linked_list *ref_tmp = conf->references;
+
+   while (ref_tmp)
+   {
+      pathname_make_slashes_portable(ref_tmp->path);
+      fprintf(file, "#reference \"%s\"\n", ref_tmp->path);
+      ref_tmp = ref_tmp->next;
+   }
+
+   if (sort)
+      list = config_file_merge_sort_linked_list(
+            (struct config_entry_list*)conf->entries,
+            config_file_sort_compare_func);
+   else
+      list = (struct config_entry_list*)conf->entries;
+
+   conf->entries = list;
+
+   while (list)
+   {
+      if (!list->readonly && list->key)
+         fprintf(file, "%s = \"%s\"\n", list->key, list->value);
+      list = list->next;
+   }
+
+   /* Config files are read from the top down - if
+    * duplicate entries are found then the topmost
+    * one in the list takes precedence. This means
+    * '#include' directives must go *after* individual
+    * config entries, otherwise they will override
+    * any custom-set values */
+   while (includes)
+   {
+      fprintf(file, "#include \"%s\"\n", includes->path);
+      includes = includes->next;
+   }
+}
+
+/**
+ * config_get_entry_list_head:
+ *
+ * Leaf function.
+ **/
+bool config_get_entry_list_head(config_file_t *conf,
+      struct config_file_entry *entry)
+{
+   const struct config_entry_list *head = conf->entries;
+
+   if (!head)
+      return false;
+
+   entry->key   = head->key;
+   entry->value = head->value;
+   entry->next  = head->next;
+   return true;
+}
+
+/**
+ * config_get_entry_list_next:
+ *
+ * Leaf function.
+ **/
+bool config_get_entry_list_next(struct config_file_entry *entry)
+{
+   const struct config_entry_list *next = entry->next;
+
+   if (!next)
+      return false;
+
+   entry->key   = next->key;
+   entry->value = next->value;
+   entry->next  = next->next;
+   return true;
+}
diff --git a/deps/libretro-common/file/config_file_userdata.c b/deps/libretro-common/file/config_file_userdata.c
new file mode 100644 (file)
index 0000000..799ce5f
--- /dev/null
@@ -0,0 +1,171 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (config_file_userdata.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <file/file_path.h>
+#include <lists/string_list.h>
+
+#include <file/config_file_userdata.h>
+
+int config_userdata_get_float(void *userdata, const char *key_str,
+      float *value, float default_value)
+{
+   bool got;
+   char key[2][256];
+   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
+
+   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
+   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
+
+   got = config_get_float  (usr->conf, key[0], value);
+   got = got || config_get_float(usr->conf, key[1], value);
+
+   if (!got)
+      *value = default_value;
+   return got;
+}
+
+int config_userdata_get_int(void *userdata, const char *key_str,
+      int *value, int default_value)
+{
+   bool got;
+   char key[2][256];
+   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
+
+   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
+   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
+
+   got = config_get_int  (usr->conf, key[0], value);
+   got = got || config_get_int(usr->conf, key[1], value);
+
+   if (!got)
+      *value = default_value;
+   return got;
+}
+
+int config_userdata_get_hex(void *userdata, const char *key_str,
+      unsigned *value, unsigned default_value)
+{
+   bool got;
+   char key[2][256];
+   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
+
+   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
+   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
+
+   got = config_get_hex(usr->conf, key[0], value);
+   got = got || config_get_hex(usr->conf, key[1], value);
+
+   if (!got)
+      *value = default_value;
+   return got;
+}
+
+int config_userdata_get_float_array(void *userdata, const char *key_str,
+      float **values, unsigned *out_num_values,
+      const float *default_values, unsigned num_default_values)
+{
+   char key[2][256];
+   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
+   char *str = NULL;
+
+   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
+   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
+
+   if (  config_get_string(usr->conf, key[0], &str) ||
+         config_get_string(usr->conf, key[1], &str))
+   {
+      unsigned i;
+      struct string_list list = {0};
+      string_list_initialize(&list);
+      string_split_noalloc(&list, str, " ");
+      *values = (float*)calloc(list.size, sizeof(float));
+      for (i = 0; i < list.size; i++)
+         (*values)[i] = (float)strtod(list.elems[i].data, NULL);
+      *out_num_values = (unsigned)list.size;
+      string_list_deinitialize(&list);
+      free(str);
+      return true;
+   }
+
+   *values = (float*)calloc(num_default_values, sizeof(float));
+   memcpy(*values, default_values, sizeof(float) * num_default_values);
+   *out_num_values = num_default_values;
+   return false;
+}
+
+int config_userdata_get_int_array(void *userdata, const char *key_str,
+      int **values, unsigned *out_num_values,
+      const int *default_values, unsigned num_default_values)
+{
+   char key[2][256];
+   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
+   char *str = NULL;
+   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
+   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
+
+   if (  config_get_string(usr->conf, key[0], &str) ||
+         config_get_string(usr->conf, key[1], &str))
+   {
+      unsigned i;
+      struct string_list list = {0};
+      string_list_initialize(&list);
+      string_split_noalloc(&list, str, " ");
+      *values = (int*)calloc(list.size, sizeof(int));
+      for (i = 0; i < list.size; i++)
+         (*values)[i] = (int)strtod(list.elems[i].data, NULL);
+      *out_num_values = (unsigned)list.size;
+      string_list_deinitialize(&list);
+      free(str);
+      return true;
+   }
+
+   *values = (int*)calloc(num_default_values, sizeof(int));
+   memcpy(*values, default_values, sizeof(int) * num_default_values);
+   *out_num_values = num_default_values;
+   return false;
+}
+
+int config_userdata_get_string(void *userdata, const char *key_str,
+      char **output, const char *default_output)
+{
+   char key[2][256];
+   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
+   char *str = NULL;
+   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
+   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
+
+   if (  config_get_string(usr->conf, key[0], &str) ||
+         config_get_string(usr->conf, key[1], &str))
+   {
+      *output = str;
+      return true;
+   }
+
+   *output = strdup(default_output);
+   return false;
+}
+
+void config_userdata_free(void *ptr)
+{
+   if (ptr)
+      free(ptr);
+}
diff --git a/deps/libretro-common/file/file_path.c b/deps/libretro-common/file/file_path.c
new file mode 100644 (file)
index 0000000..3b4e642
--- /dev/null
@@ -0,0 +1,1452 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_path.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <locale.h>
+
+#include <sys/stat.h>
+
+#include <boolean.h>
+#include <file/file_path.h>
+#include <retro_miscellaneous.h>
+#include <string/stdstring.h>
+#include <time/rtime.h>
+
+/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+#ifdef __HAIKU__
+#include <kernel/image.h>
+#endif
+#ifndef __MACH__
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+#endif
+#include <retro_miscellaneous.h>
+#include <encodings/utf.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h> /* stat() is defined here */
+#endif
+
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+#ifdef __WINRT__
+#include <uwp/uwp_func.h>
+#endif
+#endif
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+
+#endif
+
+/* Time format strings with AM-PM designation require special
+ * handling due to platform dependence */
+void strftime_am_pm(char *s, size_t len, const char* format,
+      const void *ptr)
+{
+   char *local = NULL;
+   const struct tm *timeptr = (const struct tm*)ptr;
+
+   /* Ensure correct locale is set
+    * > Required for localised AM/PM strings */
+   setlocale(LC_TIME, "");
+
+   strftime(s, len, format, timeptr);
+#if !(defined(__linux__) && !defined(ANDROID))
+   if ((local = local_to_utf8_string_alloc(s)))
+   {
+      if (!string_is_empty(local))
+         strlcpy(s, local, len);
+
+      free(local);
+      local = NULL;
+   }
+#endif
+}
+
+/**
+ * Create a new linked list with one node in it
+ * The path on this node will be set to NULL
+**/
+struct path_linked_list* path_linked_list_new(void)
+{
+   struct path_linked_list* paths_list = (struct path_linked_list*)malloc(sizeof(*paths_list));
+   paths_list->next = NULL;
+   paths_list->path = NULL;
+   return paths_list;
+}
+
+/**
+ * path_linked_list_free:
+ *
+ * Free the entire linked list
+ **/
+void path_linked_list_free(struct path_linked_list *in_path_linked_list)
+{
+   struct path_linked_list *node_tmp = (struct path_linked_list*)in_path_linked_list;
+   while (node_tmp)
+   {
+      struct path_linked_list *hold = NULL;
+      if (node_tmp->path)
+         free(node_tmp->path);
+      hold     = (struct path_linked_list*)node_tmp;
+      node_tmp = node_tmp->next;
+      if (hold)
+         free(hold);
+   }
+}
+
+/**
+ * path_linked_list_add_path:
+ *
+ * Add a node to the linked list with this path
+ * If the first node's path if it's not yet set the path
+ * on this node instead
+**/
+void path_linked_list_add_path(struct path_linked_list *in_path_linked_list,
+      char *path)
+{
+    /* If the first item does not have a path this is
+      a list which has just been created, so we just fill 
+      the path for the first item
+   */
+   if (!in_path_linked_list->path)
+      in_path_linked_list->path = strdup(path);
+   else
+   {  
+      struct path_linked_list *node = (struct path_linked_list*) malloc(sizeof(*node));
+
+      if (node)
+      {
+         struct path_linked_list *head = in_path_linked_list;
+
+         node->next                    = NULL;
+         node->path                    = strdup(path);
+
+         if (head)
+         {
+            while (head->next)
+               head        = head->next;
+
+            head->next     = node;
+         }
+         else
+            in_path_linked_list = node;
+      }
+   }
+}
+
+/**
+ * path_get_archive_delim:
+ * @path               : path
+ *
+ * Find delimiter of an archive file. Only the first '#'
+ * after a compression extension is considered.
+ *
+ * @return pointer to the delimiter in the path if it contains
+ * a path inside a compressed file, otherwise NULL.
+ **/
+const char *path_get_archive_delim(const char *path)
+{
+   char buf[5];
+   /* Find delimiter position
+    * > Since filenames may contain '#' characters,
+    *   must loop until we find the first '#' that
+    *   is directly *after* a compression extension */
+   const char *delim      = strchr(path, '#');
+
+   while (delim)
+   {
+      /* Check whether this is a known archive type
+       * > Note: The code duplication here is
+       *   deliberate, to maximise performance */
+      if (delim - path > 4)
+      {
+         strlcpy(buf, delim - 4, sizeof(buf));
+         buf[4] = '\0';
+
+         string_to_lower(buf);
+
+         /* Check if this is a '.zip', '.apk' or '.7z' file */
+         if (string_is_equal(buf,     ".zip") ||
+             string_is_equal(buf,     ".apk") ||
+             string_is_equal(buf + 1, ".7z"))
+            return delim;
+      }
+      else if (delim - path > 3)
+      {
+         strlcpy(buf, delim - 3, sizeof(buf));
+         buf[3] = '\0';
+
+         string_to_lower(buf);
+
+         /* Check if this is a '.7z' file */
+         if (string_is_equal(buf, ".7z"))
+            return delim;
+      }
+
+      delim++;
+      delim = strchr(delim, '#');
+   }
+
+   return NULL;
+}
+
+/**
+ * path_get_extension:
+ * @path               : path
+ *
+ * Gets extension of file. Only '.'s
+ * after the last slash are considered.
+ *
+ * @return extension part from the path.
+ **/
+const char *path_get_extension(const char *path)
+{
+   const char *ext;
+   if (!string_is_empty(path) && ((ext = (char*)strrchr(path_basename(path), '.'))))
+      return ext + 1;
+   return "";
+}
+
+/**
+ * path_get_extension_mutable:
+ * @path               : path
+ *
+ * Specialized version of path_get_extension(). Return
+ * value is mutable.
+ *
+ * Gets extension of file. Only '.'s
+ * after the last slash are considered.
+ *
+ * @return extension part from the path.
+ **/
+char *path_get_extension_mutable(const char *path)
+{
+   char *ext = NULL;
+   if (!string_is_empty(path) && ((ext = (char*)strrchr(path_basename(path), '.'))))
+      return ext;
+   return NULL;
+}
+
+/**
+ * path_remove_extension:
+ * @path               : path
+ *
+ * Mutates path by removing its extension. Removes all
+ * text after and including the last '.'.
+ * Only '.'s after the last slash are considered.
+ *
+ * @return
+ * 1) If path has an extension, returns path with the
+ *    extension removed.
+ * 2) If there is no extension, returns NULL.
+ * 3) If path is empty or NULL, returns NULL
+ **/
+char *path_remove_extension(char *path)
+{
+   char *last = !string_is_empty(path)
+      ? (char*)strrchr(path_basename(path), '.') : NULL;
+   if (!last)
+      return NULL;
+   if (*last)
+      *last = '\0';
+   return path;
+}
+
+/**
+ * path_is_compressed_file:
+ * @path               : path
+ *
+ * Checks if path is a compressed file.
+ *
+ * @return true if path is a compressed file, otherwise false.
+ **/
+bool path_is_compressed_file(const char* path)
+{
+   const char *ext = path_get_extension(path);
+   if (!string_is_empty(ext))
+      return (   string_is_equal_noncase(ext, "zip")
+              || string_is_equal_noncase(ext, "apk")
+              || string_is_equal_noncase(ext, "7z"));
+   return false;
+}
+
+/**
+ * fill_pathname:
+ * @out_path           : output path
+ * @in_path            : input  path
+ * @replace            : what to replace
+ * @size               : buffer size of output path
+ *
+ * FIXME: Verify
+ *
+ * Replaces filename extension with 'replace' and outputs result to out_path.
+ * The extension here is considered to be the string from the last '.'
+ * to the end.
+ *
+ * Only '.'s after the last slash are considered as extensions.
+ * If no '.' is present, in_path and replace will simply be concatenated.
+ * 'size' is buffer size of 'out_path'.
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
+ * out_path = "/foo/bar/baz/boo.asm"
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =>
+ * out_path = "/foo/bar/baz/boo"
+ *
+ * @return Length of the string copied into @out
+ */
+size_t fill_pathname(char *out_path, const char *in_path,
+      const char *replace, size_t size)
+{
+   char tmp_path[PATH_MAX_LENGTH];
+   char *tok   = NULL;
+   strlcpy(tmp_path, in_path, sizeof(tmp_path));
+   if ((tok = (char*)strrchr(path_basename(tmp_path), '.')))
+      *tok = '\0';
+
+   strlcpy(out_path, tmp_path, size);
+   return strlcat(out_path, replace, size);
+}
+
+
+/**
+ * find_last_slash:
+ * @str                : path
+ * @size               : size of path
+ *
+ * Find last slash in path. Tries to find
+ * a backslash on Windows too which takes precedence
+ * over regular slash.
+
+ * @return pointer to last slash/backslash found in @str.
+ **/
+char *find_last_slash(const char *str)
+{
+   const char *slash     = strrchr(str, '/');
+#ifdef _WIN32
+   const char *backslash = strrchr(str, '\\');
+
+   if (!slash || (backslash > slash))
+      return (char*)backslash;
+#endif
+   return (char*)slash;
+}
+
+/**
+ * fill_pathname_slash:
+ * @path               : path
+ * @size               : size of path
+ *
+ * Assumes path is a directory. Appends a slash
+ * if not already there.
+ **/
+void fill_pathname_slash(char *path, size_t size)
+{
+   size_t path_len;
+   const char *last_slash = find_last_slash(path);
+
+   if (!last_slash)
+   {
+      strlcat(path, PATH_DEFAULT_SLASH(), size);
+      return;
+   }
+
+   path_len               = strlen(path);
+   /* Try to preserve slash type. */
+   if (last_slash != (path + path_len - 1))
+   {
+      path[path_len]   = last_slash[0];
+      path[path_len+1] = '\0';
+   }
+}
+
+/**
+ * fill_pathname_dir:
+ * @in_dir             : input directory path
+ * @in_basename        : input basename to be appended to @in_dir
+ * @replace            : replacement to be appended to @in_basename
+ * @size               : size of buffer
+ *
+ * Appends basename of 'in_basename', to 'in_dir', along with 'replace'.
+ * Basename of in_basename is the string after the last '/' or '\\',
+ * i.e the filename without directories.
+ *
+ * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
+ * 'size' is buffer size of 'in_dir'.
+ *
+ * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
+ * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
+ **/
+size_t fill_pathname_dir(char *in_dir, const char *in_basename,
+      const char *replace, size_t size)
+{
+   const char *base = NULL;
+
+   fill_pathname_slash(in_dir, size);
+   base = path_basename(in_basename);
+   strlcat(in_dir, base, size);
+   return strlcat(in_dir, replace, size);
+}
+
+/**
+ * fill_pathname_base:
+ * @out                : output path
+ * @in_path            : input path
+ * @size               : size of output path
+ *
+ * Copies basename of @in_path into @out_path.
+ *
+ * @return Length of the string copied into @out
+ **/
+size_t fill_pathname_base(char *out, const char *in_path, size_t size)
+{
+   const char     *ptr = path_basename(in_path);
+   if (ptr)
+      return strlcpy(out, ptr, size);
+   return strlcpy(out, in_path, size);
+}
+
+/**
+ * fill_pathname_basedir:
+ * @out_dir            : output directory
+ * @in_path            : input path
+ * @size               : size of output directory
+ *
+ * Copies base directory of @in_path into @out_path.
+ * If in_path is a path without any slashes (relative current directory),
+ * @out_path will get path "./".
+ **/
+void fill_pathname_basedir(char *out_dir,
+      const char *in_path, size_t size)
+{
+   if (out_dir != in_path)
+      strlcpy(out_dir, in_path, size);
+   path_basedir(out_dir);
+}
+
+/**
+ * fill_pathname_parent_dir_name:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies only the parent directory name of @in_dir into @out_dir.
+ * The two buffers must not overlap. Removes trailing '/'.
+ *
+ * @return true on success, false if a slash was not found in the path.
+ **/
+bool fill_pathname_parent_dir_name(char *out_dir,
+      const char *in_dir, size_t size)
+{
+   char *temp   = strdup(in_dir);
+   char *last   = find_last_slash(temp);
+
+   if (last && last[1] == 0)
+   {
+      *last     = '\0';
+      last      = find_last_slash(temp);
+   }
+
+   /* Cut the last part of the string (the filename) after the slash,
+      leaving the directory name (or nested directory names) only. */
+   if (last)
+      *last     = '\0';
+
+   /* Point in_dir to the address of the last slash. */
+   /* If find_last_slash returns NULL, it means there was no slash in temp,
+      so use temp as-is. */
+   if (!(in_dir = find_last_slash(temp)))
+       in_dir   = temp;
+
+   if (in_dir && in_dir[1])
+   {
+       /* If path starts with an slash, eliminate it. */
+       if (path_is_absolute(in_dir))
+           strlcpy(out_dir, in_dir + 1, size);
+       else
+           strlcpy(out_dir, in_dir, size);
+       free(temp);
+       return true;
+   }
+
+   free(temp);
+   return false;
+}
+
+/**
+ * fill_pathname_parent_dir:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies parent directory of @in_dir into @out_dir.
+ * Assumes @in_dir is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory,
+ * @out_dir will be an empty string.
+ **/
+void fill_pathname_parent_dir(char *out_dir,
+      const char *in_dir, size_t size)
+{
+   size_t len = 0;
+   if (out_dir != in_dir)
+      len = strlcpy(out_dir, in_dir, size);
+   else
+      len = strlen(out_dir);
+   path_parent_dir(out_dir, len);
+}
+
+/**
+ * fill_dated_filename:
+ * @out_filename       : output filename
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by 'RetroArch', and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
+ **/
+size_t fill_dated_filename(char *out_filename,
+      const char *ext, size_t size)
+{
+   time_t cur_time = time(NULL);
+   struct tm tm_;
+
+   rtime_localtime(&cur_time, &tm_);
+
+   strftime(out_filename, size,
+         "RetroArch-%m%d-%H%M%S", &tm_);
+   return strlcat(out_filename, ext, size);
+}
+
+/**
+ * fill_str_dated_filename:
+ * @out_filename       : output filename
+ * @in_str             : input string
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by the string @in_str, and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_str_dated_filename(char *out_filename,
+      const char *in_str, const char *ext, size_t size)
+{
+   char format[NAME_MAX_LENGTH];
+   struct tm tm_;
+   time_t cur_time = time(NULL);
+
+   rtime_localtime(&cur_time, &tm_);
+
+   strlcpy(out_filename, in_str, size);
+   if (string_is_empty(ext))
+   {
+      strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
+      return strlcat(out_filename, format, size);
+   }
+   strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_);
+   strlcat(out_filename, format, size);
+   return strlcat(out_filename, ext, size);
+}
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir(char *path)
+{
+   char *last = NULL;
+   if (!path || path[0] == '\0' || path[1] == '\0')
+      return;
+
+   if ((last = find_last_slash(path)))
+      last[1] = '\0';
+   else
+   {
+      path[0] = '.';
+      path[1] = PATH_DEFAULT_SLASH_C();
+      path[2] = '\0';
+   }
+}
+
+/**
+ * path_parent_dir:
+ * @path               : path
+ * @len                : length of @path
+ *
+ * Extracts parent directory by mutating path.
+ * Assumes that path is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory, returns empty string
+ **/
+void path_parent_dir(char *path, size_t len)
+{
+   if (!path)
+      return;
+   
+   if (len && PATH_CHAR_IS_SLASH(path[len - 1]))
+   {
+      bool path_was_absolute = path_is_absolute(path);
+
+      path[len - 1] = '\0';
+
+      if (path_was_absolute && !find_last_slash(path))
+      {
+         /* We removed the only slash from what used to be an absolute path.
+          * On Linux, this goes from "/" to an empty string and everything works fine,
+          * but on Windows, we went from C:\ to C:, which is not a valid path and that later
+          * gets errornously treated as a relative one by path_basedir and returns "./".
+          * What we really wanted is an empty string. */
+         path[0] = '\0';
+         return;
+      }
+   }
+   path_basedir(path);
+}
+
+/**
+ * path_basename:
+ * @path               : path
+ *
+ * Get basename from @path.
+ *
+ * @return basename from path.
+ **/
+const char *path_basename(const char *path)
+{
+   /* We cut at the first compression-related hash */
+   const char *delim = path_get_archive_delim(path);
+   if (delim)
+      return delim + 1;
+
+   {
+      /* We cut at the last slash */
+      const char *last  = find_last_slash(path);
+      if (last)
+         return last + 1;
+   }
+
+   return path;
+}
+
+/* Specialized version */
+/**
+ * path_basename_nocompression:
+ * @path               : path
+ *
+ * Specialized version of path_basename().
+ * Get basename from @path.
+ *
+ * @return basename from path.
+ **/
+const char *path_basename_nocompression(const char *path)
+{
+   /* We cut at the last slash */
+   const char *last  = find_last_slash(path);
+   if (last)
+      return last + 1;
+   return path;
+}
+
+/**
+ * path_is_absolute:
+ * @path               : path
+ *
+ * Checks if @path is an absolute path or a relative path.
+ *
+ * @return true if path is absolute, false if path is relative.
+ **/
+bool path_is_absolute(const char *path)
+{
+   if (string_is_empty(path))
+      return false;
+
+   if (path[0] == '/')
+      return true;
+
+#if defined(_WIN32)
+   /* Many roads lead to Rome...
+    * Note: Drive letter can only be 1 character long */
+   return ( string_starts_with_size(path,     "\\\\", STRLEN_CONST("\\\\"))
+         || string_starts_with_size(path + 1, ":/",   STRLEN_CONST(":/")) 
+         || string_starts_with_size(path + 1, ":\\",  STRLEN_CONST(":\\")));
+#elif defined(__wiiu__) || defined(VITA)
+   {
+      const char *seperator = strchr(path, ':');
+      return (seperator && (seperator[1] == '/'));
+   }
+#endif
+
+   return false;
+}
+
+/**
+ * path_resolve_realpath:
+ * @buf                : input and output buffer for path
+ * @size               : size of buffer
+ * @resolve_symlinks   : whether to resolve symlinks or not
+ *
+ * Resolves use of ".", "..", multiple slashes etc in absolute paths.
+ *
+ * Relative paths are rebased on the current working dir.
+ *
+ * @return @buf if successful, NULL otherwise.
+ * Note: Not implemented on consoles
+ * Note: Symlinks are only resolved on Unix-likes
+ * Note: The current working dir might not be what you expect,
+ *       e.g. on Android it is "/"
+ *       Use of fill_pathname_resolve_relative() should be prefered
+ **/
+char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks)
+{
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+#ifdef _WIN32
+   char *ret = NULL;
+   wchar_t *rel_path = utf8_to_utf16_string_alloc(buf);
+
+   if (rel_path)
+   {
+      wchar_t abs_path[PATH_MAX_LENGTH];
+
+      if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH))
+      {
+         char *tmp = utf16_to_utf8_string_alloc(abs_path);
+
+         if (tmp)
+         {
+            strlcpy(buf, tmp, size);
+            free(tmp);
+            ret = buf;
+         }
+      }
+
+      free(rel_path);
+   }
+
+   return ret;
+#else
+   char tmp[PATH_MAX_LENGTH];
+   size_t t;
+   char *p;
+   const char *next;
+   const char *buf_end;
+
+   if (resolve_symlinks)
+   {
+      strlcpy(tmp, buf, sizeof(tmp));
+
+      /* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in buf.
+       * Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways.
+       * POSIX 2008 can automatically allocate for you,
+       * but don't rely on that. */
+      if (!realpath(tmp, buf))
+      {
+         strlcpy(buf, tmp, size);
+         return NULL;
+      }
+
+      return buf;
+   }
+
+   t       = 0; /* length of output */
+   buf_end = buf + strlen(buf);
+
+   if (!path_is_absolute(buf))
+   {
+      size_t len;
+      /* rebase on working directory */
+      if (!getcwd(tmp, PATH_MAX_LENGTH-1))
+         return NULL;
+
+      len = strlen(tmp);
+      t += len;
+
+      if (tmp[len-1] != '/')
+         tmp[t++] = '/';
+
+      if (string_is_empty(buf))
+         goto end;
+
+      p = buf;
+   }
+   else
+   {
+      /* UNIX paths can start with multiple '/', copy those */
+      for (p = buf; *p == '/'; p++)
+         tmp[t++] = '/';
+   }
+
+   /* p points to just after a slash while 'next' points to the next slash
+    * if there are no slashes, they point relative to where one would be */
+   do
+   {
+      if (!(next = strchr(p, '/')))
+         next = buf_end;
+
+      if ((next - p == 2 && p[0] == '.' && p[1] == '.'))
+      {
+         p += 3;
+
+         /* fail for illegal /.., //.. etc */
+         if (t == 1 || tmp[t-2] == '/')
+            return NULL;
+
+         /* delete previous segment in tmp by adjusting size t
+          * tmp[t-1] == '/', find '/' before that */
+         t = t-2;
+         while (tmp[t] != '/')
+            t--;
+         t++;
+      }
+      else if (next - p == 1 && p[0] == '.')
+         p += 2;
+      else if (next - p == 0)
+         p += 1;
+      else
+      {
+         /* fail when truncating */
+         if (t + next-p+1 > PATH_MAX_LENGTH-1)
+            return NULL;
+
+         while (p <= next)
+            tmp[t++] = *p++;
+      }
+   }while(next < buf_end);
+   
+
+end:
+   tmp[t] = '\0';
+   strlcpy(buf, tmp, size);
+   return buf;
+#endif
+#endif
+   return NULL;
+}
+
+/**
+ * path_relative_to:
+ * @out                : buffer to write the relative path to
+ * @path               : path to be expressed relatively
+ * @base               : base directory to start out on
+ * @size               : size of output buffer
+ *
+ * Turns @path into a path relative to @base and writes it to @out.
+ *
+ * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
+ * Both @path and @base are assumed to be absolute paths without "." or "..".
+ *
+ * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg
+ *
+ * @return Length of the string copied into @out
+ **/
+size_t path_relative_to(char *out,
+      const char *path, const char *base, size_t size)
+{
+   size_t i, j;
+   const char *trimmed_path, *trimmed_base;
+
+#ifdef _WIN32
+   /* For different drives, return absolute path */
+   if (
+            path
+         && base
+         && path[0] != '\0' 
+         && path[1] != '\0'
+         && base[0] != '\0'
+         && base[1] != '\0'
+         && path[1] == ':' 
+         && base[1] == ':'
+         && path[0] != base[0])
+      return strlcpy(out, path, size);
+#endif
+
+   /* Trim common beginning */
+   for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)
+      if (path[i] == PATH_DEFAULT_SLASH_C())
+         j = i + 1;
+
+   trimmed_path = path+j;
+   trimmed_base = base+i;
+
+   /* Each segment of base turns into ".." */
+   out[0] = '\0';
+   for (i = 0; trimmed_base[i]; i++)
+      if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
+         strlcat(out, ".." PATH_DEFAULT_SLASH(), size);
+
+   return strlcat(out, trimmed_path, size);
+}
+
+/**
+ * fill_pathname_resolve_relative:
+ * @out_path           : output path
+ * @in_refpath         : input reference path
+ * @in_path            : input path
+ * @size               : size of @out_path
+ *
+ * Joins basedir of @in_refpath together with @in_path.
+ * If @in_path is an absolute path, out_path = in_path.
+ * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
+ * out_path = "/foo/bar/foobar.cg".
+ **/
+void fill_pathname_resolve_relative(char *out_path,
+      const char *in_refpath, const char *in_path, size_t size)
+{
+   if (path_is_absolute(in_path))
+   {
+      strlcpy(out_path, in_path, size);
+      return;
+   }
+
+   if (out_path != in_refpath)
+      strlcpy(out_path, in_refpath, size);
+   path_basedir(out_path);
+   strlcat(out_path, in_path, size);
+   path_resolve_realpath(out_path, size, false);
+}
+
+/**
+ * fill_pathname_join:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together.
+ * Makes sure not to get  two consecutive slashes
+ * between directory and path.
+ *
+ * Deprecated. Use fill_pathname_join_special() instead
+ * if you can ensure @dir and @out_path won't overlap.
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_pathname_join(char *out_path,
+      const char *dir, const char *path, size_t size)
+{
+   if (out_path != dir)
+      strlcpy(out_path, dir, size);
+   if (*out_path)
+      fill_pathname_slash(out_path, size);
+   return strlcat(out_path, path, size);
+}
+
+/**
+ * fill_pathname_join_special:
+ * @out_path           : output path
+ * @dir                : directory. Cannot be identical to @out_path
+ * @path               : path
+ * @size               : size of output path
+ *
+ *
+ * Specialized version of fill_pathname_join.
+ * Unlike fill_pathname_join(),
+ * @dir and @out_path CANNOT be identical.
+ *
+ * Joins a directory (@dir) and path (@path) together.
+ * Makes sure not to get  two consecutive slashes
+ * between directory and path.
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_pathname_join_special(char *out_path,
+      const char *dir, const char *path, size_t size)
+{
+   size_t len = strlcpy(out_path, dir, size);
+
+   if (*out_path)
+   {
+      const char *last_slash = find_last_slash(out_path);
+      if (last_slash)
+      {
+         /* Try to preserve slash type. */
+         if (last_slash != (out_path + len - 1))
+         {
+            out_path[len]   = last_slash[0];
+            out_path[len+1] = '\0';
+         }
+      }
+      else
+      {
+         out_path[len]      = PATH_DEFAULT_SLASH_C();
+         out_path[len+1]    = '\0';
+      }
+   }
+
+   return strlcat(out_path, path, size);
+}
+
+size_t fill_pathname_join_special_ext(char *out_path,
+      const char *dir,  const char *path,
+      const char *last, const char *ext,
+      size_t size)
+{
+   fill_pathname_join(out_path, dir, path, size);
+   if (*out_path)
+      fill_pathname_slash(out_path, size);
+
+   strlcat(out_path, last, size);
+   return strlcat(out_path, ext, size);
+}
+
+/**
+ * fill_pathname_join_delim:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @delim              : delimiter
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together
+ * using the given delimiter (@delim).
+ **/
+size_t fill_pathname_join_delim(char *out_path, const char *dir,
+      const char *path, const char delim, size_t size)
+{
+   size_t copied;
+   /* behavior of strlcpy is undefined if dst and src overlap */
+   if (out_path == dir)
+      copied          = strlen(dir);
+   else
+      copied          = strlcpy(out_path, dir, size);
+
+   out_path[copied]   = delim;
+   out_path[copied+1] = '\0';
+
+   if (path)
+      return strlcat(out_path, path, size);
+   return copied;
+}
+
+size_t fill_pathname_expand_special(char *out_path,
+      const char *in_path, size_t size)
+{
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+   char *app_dir = NULL;
+   if (in_path[0] == '~')
+   {
+      app_dir    = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
+      fill_pathname_home_dir(app_dir, PATH_MAX_LENGTH * sizeof(char));
+   }
+   else if (in_path[0] == ':')
+   {
+      app_dir    = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
+      app_dir[0] = '\0';
+      fill_pathname_application_dir(app_dir, PATH_MAX_LENGTH * sizeof(char));
+   }
+
+   if (app_dir)
+   {
+      if (*app_dir)
+      {
+         size_t src_size = strlcpy(out_path, app_dir, size);
+
+         out_path       += src_size;
+         size           -= src_size;
+
+         if (!PATH_CHAR_IS_SLASH(out_path[-1]))
+         {
+            src_size  = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
+
+            out_path += src_size;
+            size     -= src_size;
+         }
+
+         in_path += 2;
+      }
+
+      free(app_dir);
+   }
+#endif
+   return strlcpy(out_path, in_path, size);
+}
+
+size_t fill_pathname_abbreviate_special(char *out_path,
+      const char *in_path, size_t size)
+{
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+   unsigned i;
+   const char *candidates[3];
+   const char *notations[3];
+   char application_dir[PATH_MAX_LENGTH];
+   char home_dir[PATH_MAX_LENGTH];
+
+   application_dir[0] = '\0';
+
+   /* application_dir could be zero-string. Safeguard against this.
+    *
+    * Keep application dir in front of home, moving app dir to a
+    * new location inside home would break otherwise. */
+
+   /* ugly hack - use application_dir pointer
+    * before filling it in. C89 reasons */
+   candidates[0] = application_dir;
+   candidates[1] = home_dir;
+   candidates[2] = NULL;
+
+   notations [0] = ":";
+   notations [1] = "~";
+   notations [2] = NULL;
+
+   fill_pathname_application_dir(application_dir, sizeof(application_dir));
+   fill_pathname_home_dir(home_dir, sizeof(home_dir));
+
+   for (i = 0; candidates[i]; i++)
+   {
+      if (!string_is_empty(candidates[i]) &&
+          string_starts_with(in_path, candidates[i]))
+      {
+         size_t src_size  = strlcpy(out_path, notations[i], size);
+
+         out_path        += src_size;
+         size            -= src_size;
+         in_path         += strlen(candidates[i]);
+
+         if (!PATH_CHAR_IS_SLASH(*in_path))
+         {
+            strcpy_literal(out_path, PATH_DEFAULT_SLASH());
+            out_path++;
+            size--;
+         }
+
+         break; /* Don't allow more abbrevs to take place. */
+      }
+   }
+#endif
+   return strlcpy(out_path, in_path, size);
+}
+
+/**
+ * pathname_conform_slashes_to_os:
+ *
+ * @path               : path
+ *
+ * Leaf function.
+ *
+ * Changes the slashes to the correct kind for the os 
+ * So forward slash on linux and backslash on Windows
+ **/
+void pathname_conform_slashes_to_os(char *path)
+{
+   /* Conform slashes to os standard so we get proper matching */
+   char *p;
+   for (p = path; *p; p++)
+      if (*p == '/' || *p == '\\')
+         *p = PATH_DEFAULT_SLASH_C();
+}
+
+/**
+ * pathname_make_slashes_portable:
+ * @path               : path
+ *
+ * Leaf function.
+ *
+ * Change all slashes to forward so they are more 
+ * portable between Windows and Linux
+ **/
+void pathname_make_slashes_portable(char *path)
+{
+   /* Conform slashes to os standard so we get proper matching */
+   char *p;
+   for (p = path; *p; p++)
+      if (*p == '/' || *p == '\\')
+         *p = '/';
+}
+
+/**
+ * get_pathname_num_slashes:
+ * @in_path            : input path
+ *
+ * Leaf function.
+ *
+ * Get the number of slashes in a path.
+ *
+ * @return number of slashes found in @in_path.
+ **/
+static int get_pathname_num_slashes(const char *in_path)
+{
+   int num_slashes = 0;
+   int i = 0;
+
+   for (i = 0; i < PATH_MAX_LENGTH; i++)
+   {
+      if (PATH_CHAR_IS_SLASH(in_path[i]))
+         num_slashes++;
+      if (in_path[i] == '\0')
+         break;
+   }
+
+   return num_slashes;
+}
+
+/**
+ * fill_pathname_abbreviated_or_relative:
+ *
+ * Fills the supplied path with either the abbreviated path or 
+ * the relative path, which ever one has less depth / number of slashes
+ * 
+ * If lengths of abbreviated and relative paths are the same,
+ * the relative path will be used
+ * @in_path can be an absolute, relative or abbreviated path
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_pathname_abbreviated_or_relative(char *out_path,
+      const char *in_refpath, const char *in_path, size_t size)
+{
+   char in_path_conformed[PATH_MAX_LENGTH];
+   char in_refpath_conformed[PATH_MAX_LENGTH];
+   char expanded_path[PATH_MAX_LENGTH];
+   char absolute_path[PATH_MAX_LENGTH];
+   char relative_path[PATH_MAX_LENGTH];
+   char abbreviated_path[PATH_MAX_LENGTH];
+   
+   expanded_path[0]        = '\0';
+   absolute_path[0]        = '\0';
+   relative_path[0]        = '\0';
+   abbreviated_path[0]     = '\0';
+
+   strlcpy(in_path_conformed, in_path, sizeof(in_path_conformed));
+   strlcpy(in_refpath_conformed, in_refpath, sizeof(in_refpath_conformed));
+
+   pathname_conform_slashes_to_os(in_path_conformed);
+   pathname_conform_slashes_to_os(in_refpath_conformed);
+
+   /* Expand paths which start with :\ to an absolute path */
+   fill_pathname_expand_special(expanded_path,
+         in_path_conformed, sizeof(expanded_path));
+
+   /* Get the absolute path if it is not already */
+   if (path_is_absolute(expanded_path))
+      strlcpy(absolute_path, expanded_path, PATH_MAX_LENGTH);
+   else
+      fill_pathname_resolve_relative(absolute_path,
+            in_refpath_conformed, in_path_conformed, PATH_MAX_LENGTH);
+
+   pathname_conform_slashes_to_os(absolute_path);
+
+   /* Get the relative path and see how many directories long it is */
+   path_relative_to(relative_path, absolute_path,
+         in_refpath_conformed, sizeof(relative_path));
+
+   /* Get the abbreviated path and see how many directories long it is */
+   fill_pathname_abbreviate_special(abbreviated_path,
+         absolute_path, sizeof(abbreviated_path));
+
+   /* Use the shortest path, preferring the relative path*/
+   if (  get_pathname_num_slashes(relative_path) <= 
+         get_pathname_num_slashes(abbreviated_path))
+      return strlcpy(out_path, relative_path, size);
+   return strlcpy(out_path, abbreviated_path, size);
+}
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir_wrapper(char *path)
+{
+   char *last = NULL;
+   if (!path || path[0] == '\0' || path[1] == '\0')
+      return;
+
+#ifdef HAVE_COMPRESSION
+   /* We want to find the directory with the archive in basedir. */
+   if ((last = (char*)path_get_archive_delim(path)))
+      *last = '\0';
+#endif
+
+   if ((last = find_last_slash(path)))
+      last[1] = '\0';
+   else
+   {
+      path[0] = '.';
+      path[1] = PATH_DEFAULT_SLASH_C();
+      path[2] = '\0';
+   }
+}
+
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+void fill_pathname_application_path(char *s, size_t len)
+{
+   size_t i;
+#ifdef __APPLE__
+  CFBundleRef bundle = CFBundleGetMainBundle();
+#endif
+#ifdef _WIN32
+   DWORD ret = 0;
+   wchar_t wstr[PATH_MAX_LENGTH] = {0};
+#endif
+#ifdef __HAIKU__
+   image_info info;
+   int32_t cookie = 0;
+#endif
+   (void)i;
+
+   if (!len)
+      return;
+
+#if defined(_WIN32)
+#ifdef LEGACY_WIN32
+   ret    = GetModuleFileNameA(NULL, s, len);
+#else
+   ret    = GetModuleFileNameW(NULL, wstr, ARRAY_SIZE(wstr));
+
+   if (*wstr)
+   {
+      char *str = utf16_to_utf8_string_alloc(wstr);
+
+      if (str)
+      {
+         strlcpy(s, str, len);
+         free(str);
+      }
+   }
+#endif
+   s[ret] = '\0';
+#elif defined(__APPLE__)
+   if (bundle)
+   {
+      CFURLRef bundle_url     = CFBundleCopyBundleURL(bundle);
+      CFStringRef bundle_path = CFURLCopyPath(bundle_url);
+      CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8);
+#ifdef HAVE_COCOATOUCH
+      {
+         /* This needs to be done so that the path becomes 
+          * /private/var/... and this
+          * is used consistently throughout for the iOS bundle path */
+         char resolved_bundle_dir_buf[PATH_MAX_LENGTH] = {0};
+         if (realpath(s, resolved_bundle_dir_buf))
+         {
+            size_t _len = strlcpy(s, resolved_bundle_dir_buf, len - 1);
+            s[_len  ]   = '/';
+            s[_len+1]   = '\0';
+         }
+      }
+#endif
+
+      CFRelease(bundle_path);
+      CFRelease(bundle_url);
+#ifndef HAVE_COCOATOUCH
+      /* Not sure what this does but it breaks 
+       * stuff for iOS, so skipping */
+      strlcat(s, "nobin", len);
+#endif
+      return;
+   }
+#elif defined(__HAIKU__)
+   while (get_next_image_info(0, &cookie, &info) == B_OK)
+   {
+      if (info.type == B_APP_IMAGE)
+      {
+         strlcpy(s, info.name, len);
+         return;
+      }
+   }
+#elif defined(__QNX__)
+   char *buff = malloc(len);
+
+   if (_cmdname(buff))
+      strlcpy(s, buff, len);
+
+   free(buff);
+#else
+   {
+      pid_t pid;
+      static const char *exts[] = { "exe", "file", "path/a.out" };
+      char link_path[255];
+
+      link_path[0] = *s = '\0';
+      pid       = getpid();
+
+      /* Linux, BSD and Solaris paths. Not standardized. */
+      for (i = 0; i < ARRAY_SIZE(exts); i++)
+      {
+         ssize_t ret;
+
+         snprintf(link_path, sizeof(link_path), "/proc/%u/%s",
+               (unsigned)pid, exts[i]);
+
+         if ((ret = readlink(link_path, s, len - 1)) >= 0)
+         {
+            s[ret] = '\0';
+            return;
+         }
+      }
+   }
+#endif
+}
+
+void fill_pathname_application_dir(char *s, size_t len)
+{
+#ifdef __WINRT__
+   strlcpy(s, uwp_dir_install, len);
+#else
+   fill_pathname_application_path(s, len);
+   path_basedir_wrapper(s);
+#endif
+}
+
+void fill_pathname_home_dir(char *s, size_t len)
+{
+#ifdef __WINRT__
+   const char *home = uwp_dir_data;
+#else
+   const char *home = getenv("HOME");
+#endif
+   if (home)
+      strlcpy(s, home, len);
+   else
+      *s = 0;
+}
+#endif
+
+bool is_path_accessible_using_standard_io(const char *path)
+{
+#ifdef __WINRT__
+   return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
+#else
+   return true;
+#endif
+}
diff --git a/deps/libretro-common/file/file_path_io.c b/deps/libretro-common/file/file_path_io.c
new file mode 100644 (file)
index 0000000..d8f8187
--- /dev/null
@@ -0,0 +1,149 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_path_io.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/stat.h>
+
+#include <boolean.h>
+#include <file/file_path.h>
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+#include <retro_miscellaneous.h>
+#include <string/stdstring.h>
+#define VFS_FRONTEND
+#include <vfs/vfs_implementation.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h> /* stat() is defined here */
+#endif
+
+/* TODO/FIXME - globals */
+static retro_vfs_stat_t path_stat_cb   = retro_vfs_stat_impl;
+static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
+
+void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
+{
+   const struct retro_vfs_interface* 
+      vfs_iface           = vfs_info->iface;
+
+   path_stat_cb           = retro_vfs_stat_impl;
+   path_mkdir_cb          = retro_vfs_mkdir_impl;
+
+   if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
+      return;
+
+   path_stat_cb           = vfs_iface->stat;
+   path_mkdir_cb          = vfs_iface->mkdir;
+}
+
+int path_stat(const char *path)
+{
+   return path_stat_cb(path, NULL);
+}
+
+/**
+ * path_is_directory:
+ * @path               : path
+ *
+ * Checks if path is a directory.
+ *
+ * @return true if path is a directory, otherwise false.
+ */
+bool path_is_directory(const char *path)
+{
+   return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
+}
+
+bool path_is_character_special(const char *path)
+{
+   return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
+}
+
+bool path_is_valid(const char *path)
+{
+   return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
+}
+
+int32_t path_get_size(const char *path)
+{
+   int32_t filesize = 0;
+   if (path_stat_cb(path, &filesize) != 0)
+      return filesize;
+
+   return -1;
+}
+
+/**
+ * path_mkdir:
+ * @dir                : directory
+ *
+ * Create directory on filesystem.
+ * 
+ * Recursive function.
+ *
+ * @return true if directory could be created, otherwise false.
+ **/
+bool path_mkdir(const char *dir)
+{
+   bool norecurse     = false;
+   char     *basedir  = NULL;
+
+   if (!(dir && *dir))
+      return false;
+
+   /* Use heap. Real chance of stack 
+    * overflow if we recurse too hard. */
+   if (!(basedir = strdup(dir)))
+      return false;
+
+   path_parent_dir(basedir, strlen(basedir));
+
+   if (!*basedir || !strcmp(basedir, dir))
+   {
+      free(basedir);
+      return false;
+   }
+
+   if (     path_is_directory(basedir)
+         || path_mkdir(basedir))
+      norecurse = true;
+
+   free(basedir);
+
+   if (norecurse)
+   {
+      int ret = path_mkdir_cb(dir);
+
+      /* Don't treat this as an error. */
+      if (ret == -2 && path_is_directory(dir))
+         return true;
+      else if (ret == 0)
+         return true;
+   }
+   return false;
+}
diff --git a/deps/libretro-common/file/nbio/nbio_intf.c b/deps/libretro-common/file/nbio/nbio_intf.c
new file mode 100644 (file)
index 0000000..e945a34
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nbio_intf.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <file/nbio.h>
+
+extern nbio_intf_t nbio_linux;
+extern nbio_intf_t nbio_mmap_unix;
+extern nbio_intf_t nbio_mmap_win32;
+extern nbio_intf_t nbio_stdio;
+
+#ifndef _XBOX
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1500
+
+#ifndef HAVE_MMAP_WIN32
+#define HAVE_MMAP_WIN32
+#endif
+
+#elif !defined(_MSC_VER)
+
+#ifndef HAVE_MMAP_WIN32
+#define HAVE_MMAP_WIN32
+#endif
+#endif
+#endif
+
+#endif
+
+#if defined(_linux__)
+static nbio_intf_t *internal_nbio = &nbio_linux;
+#elif defined(HAVE_MMAP) && defined(BSD)
+static nbio_intf_t *internal_nbio = &nbio_mmap_unix;
+#elif defined(HAVE_MMAP_WIN32)
+static nbio_intf_t *internal_nbio = &nbio_mmap_win32;
+#else
+static nbio_intf_t *internal_nbio = &nbio_stdio;
+#endif
+
+void *nbio_open(const char * filename, unsigned mode)
+{
+   return internal_nbio->open(filename, mode);
+}
+
+void nbio_begin_read(void *data)
+{
+   internal_nbio->begin_read(data);
+}
+
+void nbio_begin_write(void *data)
+{
+   internal_nbio->begin_write(data);
+}
+
+bool nbio_iterate(void *data)
+{
+   return internal_nbio->iterate(data);
+}
+
+void nbio_resize(void *data, size_t len)
+{
+   internal_nbio->resize(data, len);
+}
+
+void *nbio_get_ptr(void *data, size_t* len)
+{
+   return internal_nbio->get_ptr(data, len);
+}
+
+void nbio_cancel(void *data)
+{
+   internal_nbio->cancel(data);
+}
+
+void nbio_free(void *data)
+{
+   internal_nbio->free(data);
+}
diff --git a/deps/libretro-common/file/nbio/nbio_linux.c b/deps/libretro-common/file/nbio/nbio_linux.c
new file mode 100644 (file)
index 0000000..b0ae46d
--- /dev/null
@@ -0,0 +1,235 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nbio_linux.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <file/nbio.h>
+
+#if defined(__linux__)
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <linux/aio_abi.h>
+
+struct nbio_linux_t
+{
+   void* ptr;
+   aio_context_t ctx;
+   struct iocb cb;
+   size_t len;
+   int fd;
+   bool busy;
+};
+
+/* there's also a Unix AIO thingy, but it's not in glibc
+ * and we don't want more dependencies */
+
+static int io_setup(unsigned nr, aio_context_t * ctxp)
+{
+   return syscall(__NR_io_setup, nr, ctxp);
+}
+
+static int io_destroy(aio_context_t ctx)
+{
+   return syscall(__NR_io_destroy, ctx);
+}
+
+static int io_submit(aio_context_t ctx, long nr, struct iocb ** cbp)
+{
+   return syscall(__NR_io_submit, ctx, nr, cbp);
+}
+
+static int io_cancel(aio_context_t ctx, struct iocb * iocb, struct io_event * result)
+{
+   return syscall(__NR_io_cancel, ctx, iocb, result);
+}
+
+static int io_getevents(aio_context_t ctx, long min_nr, long nr,
+      struct io_event * events, struct timespec * timeout)
+{
+   return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
+}
+
+static void nbio_begin_op(struct nbio_linux_t* handle, uint16_t op)
+{
+   struct iocb * cbp         = &handle->cb;
+
+   memset(&handle->cb, 0, sizeof(handle->cb));
+
+   handle->cb.aio_fildes     = handle->fd;
+   handle->cb.aio_lio_opcode = op;
+
+   handle->cb.aio_buf        = (uint64_t)(uintptr_t)handle->ptr;
+   handle->cb.aio_offset     = 0;
+   handle->cb.aio_nbytes     = handle->len;
+
+   if (io_submit(handle->ctx, 1, &cbp) != 1)
+      abort();
+
+   handle->busy = true;
+}
+
+static void *nbio_linux_open(const char * filename, unsigned mode)
+{
+   static const int o_flags[]  =   { O_RDONLY, O_RDWR|O_CREAT|O_TRUNC, O_RDWR, O_RDONLY, O_RDWR|O_CREAT|O_TRUNC };
+
+   aio_context_t ctx           = 0;
+   struct nbio_linux_t* handle = NULL;
+   int fd                      = open(filename, o_flags[mode]|O_CLOEXEC, 0644);
+   if (fd < 0)
+      return NULL;
+
+   if (io_setup(128, &ctx) < 0)
+   {
+      close(fd);
+      return NULL;
+   }
+
+   handle       = (struct nbio_linux_t*)malloc(sizeof(struct nbio_linux_t));
+   handle->fd   = fd;
+   handle->ctx  = ctx;
+   handle->len  = lseek(fd, 0, SEEK_END);
+   handle->ptr  = malloc(handle->len);
+   handle->busy = false;
+
+   return handle;
+}
+
+static void nbio_linux_begin_read(void *data)
+{
+   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
+   if (handle)
+      nbio_begin_op(handle, IOCB_CMD_PREAD);
+}
+
+static void nbio_linux_begin_write(void *data)
+{
+   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
+   if (handle)
+      nbio_begin_op(handle, IOCB_CMD_PWRITE);
+}
+
+static bool nbio_linux_iterate(void *data)
+{
+   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
+   if (!handle)
+      return false;
+   if (handle->busy)
+   {
+      struct io_event ev;
+      if (io_getevents(handle->ctx, 0, 1, &ev, NULL) == 1)
+         handle->busy = false;
+   }
+   return !handle->busy;
+}
+
+static void nbio_linux_resize(void *data, size_t len)
+{
+   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
+   if (!handle)
+      return;
+
+   /* This works perfectly fine if this check is removed, but it
+    * won't work on other nbio implementations */
+   /* therefore, it's blocked so nobody accidentally relies on it */
+   if (len < handle->len)
+      abort();
+
+   if (ftruncate(handle->fd, len) != 0)
+      abort(); /* this one returns void and I can't find any other way
+                  for it to report failure */
+
+   handle->ptr = realloc(handle->ptr, len);
+   handle->len = len;
+}
+
+static void *nbio_linux_get_ptr(void *data, size_t* len)
+{
+   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
+   if (!handle)
+      return NULL;
+   if (len)
+      *len = handle->len;
+   if (!handle->busy)
+      return handle->ptr;
+   return NULL;
+}
+
+static void nbio_linux_cancel(void *data)
+{
+   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->busy)
+   {
+      struct io_event ev;
+      io_cancel(handle->ctx, &handle->cb, &ev);
+      handle->busy = false;
+   }
+}
+
+static void nbio_linux_free(void *data)
+{
+   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
+   if (!handle)
+      return;
+
+   io_destroy(handle->ctx);
+   close(handle->fd);
+   free(handle->ptr);
+   free(handle);
+}
+
+nbio_intf_t nbio_linux = {
+   nbio_linux_open,
+   nbio_linux_begin_read,
+   nbio_linux_begin_write,
+   nbio_linux_iterate,
+   nbio_linux_resize,
+   nbio_linux_get_ptr,
+   nbio_linux_cancel,
+   nbio_linux_free,
+   "nbio_linux",
+};
+#else
+nbio_intf_t nbio_linux = {
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   "nbio_linux",
+};
+
+#endif
diff --git a/deps/libretro-common/file/nbio/nbio_orbis.c b/deps/libretro-common/file/nbio/nbio_orbis.c
new file mode 100644 (file)
index 0000000..7f06763
--- /dev/null
@@ -0,0 +1,231 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nbio_orbis.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <file/nbio.h>
+
+#if defined(ORBIS)
+#include <stdio.h>
+#include <stdlib.h>
+#include <orbisFile.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+
+struct nbio_orbis_t
+{
+   void* data;
+   size_t progress;
+   size_t len;
+   int fd;
+   unsigned int mode;
+   /*
+    * possible values:
+    * NBIO_READ, NBIO_WRITE - obvious
+    * -1 - currently doing nothing
+    * -2 - the pointer was reallocated since the last operation
+    */
+   signed char op;
+};
+
+static void *nbio_orbis_open(const char * filename, unsigned int mode)
+{
+   static const int o_flags[]  =   { O_RDONLY, O_RDWR | O_CREAT | O_TRUNC,
+      O_RDWR, O_RDONLY, O_RDWR | O_CREAT | O_TRUNC };
+   void *buf                   = NULL;
+   struct nbio_orbis_t* handle = NULL;
+   size_t len                  = 0;
+   int fd                      = orbisOpen(filename, o_flags[mode], 0644);
+
+   if (fd < 0)
+      return NULL;
+   handle                = (struct nbio_orbis_t*)malloc(sizeof(struct nbio_orbis_t));
+
+   if (!handle)
+      goto error;
+
+   handle->fd             = fd;
+
+   switch (mode)
+   {
+      case NBIO_WRITE:
+      case BIO_WRITE:
+         break;
+      default:
+         len=orbisLseek(handle->fd, 0, SEEK_END);
+         orbisLseek(handle->fd, 0, SEEK_SET);
+         break;
+   }
+
+   handle->mode          = mode;
+
+   if (len)
+      buf                = malloc(len);
+
+   if (len && !buf)
+      goto error;
+
+   handle->data          = buf;
+   handle->len           = len;
+   handle->progress      = handle->len;
+   handle->op            = -2;
+
+   return handle;
+
+error:
+   if (handle)
+      free(handle);
+   orbisClose(fd);
+   return NULL;
+}
+
+static void nbio_orbis_begin_read(void *data)
+{
+
+   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->op >= 0)
+      return;
+
+   orbisLseek(handle->fd, 0, SEEK_SET);
+
+   handle->op       = NBIO_READ;
+   handle->progress = 0;
+}
+
+static void nbio_orbis_begin_write(void *data)
+{
+   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->op >= 0)
+      return;
+
+   orbisLseek(handle->fd, 0, SEEK_SET);
+   handle->op = NBIO_WRITE;
+   handle->progress = 0;
+}
+
+static bool nbio_orbis_iterate(void *data)
+{
+   size_t amount               = 65536;
+   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
+
+   if (!handle)
+      return false;
+
+   if (amount > handle->len - handle->progress)
+      amount = handle->len - handle->progress;
+
+   switch (handle->op)
+   {
+      case NBIO_READ:
+         if (handle->mode == BIO_READ)
+            amount = handle->len;
+         break;
+      case NBIO_WRITE:
+         if (handle->mode == BIO_WRITE)
+         {
+            size_t written = 0;
+            amount = handle->len;
+            written = orbisWrite(handle->fd, (char*)handle->data, amount);
+
+            if (written != amount)
+               return false;
+         }
+         break;
+   }
+
+   handle->progress += amount;
+
+   if (handle->progress == handle->len)
+      handle->op = -1;
+   return (handle->op < 0);
+}
+
+static void nbio_orbis_resize(void *data, size_t len)
+{
+   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->op >= 0)
+      return;
+   if (len < handle->len)
+      return;
+
+   handle->len      = len;
+   handle->data     = realloc(handle->data, handle->len);
+   handle->op       = -1;
+   handle->progress = handle->len;
+}
+
+static void *nbio_orbis_get_ptr(void *data, size_t* len)
+{
+   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
+   if (!handle)
+      return NULL;
+   if (len)
+      *len = handle->len;
+   if (handle->op == -1)
+      return handle->data;
+   return NULL;
+}
+
+static void nbio_orbis_cancel(void *data)
+{
+   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
+   if (!handle)
+      return;
+   handle->op = -1;
+   handle->progress = handle->len;
+}
+
+static void nbio_orbis_free(void *data)
+{
+   struct nbio_orbis_t *handle = (struct nbio_orbis_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->op >= 0)
+      return;
+
+   orbisClose(handle->fd);
+   free(handle->data);
+
+   handle->data = NULL;
+   free(handle);
+}
+
+nbio_intf_t nbio_orbis = {
+   nbio_orbis_open,
+   nbio_orbis_begin_read,
+   nbio_orbis_begin_write,
+   nbio_orbis_iterate,
+   nbio_orbis_resize,
+   nbio_orbis_get_ptr,
+   nbio_orbis_cancel,
+   nbio_orbis_free,
+   "nbio_orbis",
+};
+#endif
diff --git a/deps/libretro-common/file/nbio/nbio_stdio.c b/deps/libretro-common/file/nbio/nbio_stdio.c
new file mode 100644 (file)
index 0000000..e05968b
--- /dev/null
@@ -0,0 +1,303 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nbio_stdio.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#if defined(WIIU)
+#include <malloc.h>
+#endif
+
+#include <file/nbio.h>
+#include <encodings/utf.h>
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+
+#endif
+
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define ATLEAST_VC2005
+#endif
+#endif
+
+#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
+#ifndef HAVE_64BIT_OFFSETS
+#define HAVE_64BIT_OFFSETS
+#endif
+#endif
+
+struct nbio_stdio_t
+{
+   FILE* f;
+   void* data;
+   size_t progress;
+   size_t len;
+   /*
+    * possible values:
+    * NBIO_READ, NBIO_WRITE - obvious
+    * -1 - currently doing nothing
+    * -2 - the pointer was reallocated since the last operation
+    */
+   signed char op;
+   signed char mode;
+};
+
+#if !defined(_WIN32) || defined(LEGACY_WIN32)
+static const char    *stdio_modes[] = { "rb", "wb", "r+b", "rb", "wb", "r+b" };
+#else
+static const wchar_t *stdio_modes[] = { L"rb", L"wb", L"r+b", L"rb", L"wb", L"r+b" };
+#endif
+
+static int64_t fseek_wrap(FILE *f, int64_t offset, int origin)
+{
+#ifdef ATLEAST_VC2005
+   /* VC2005 and up have a special 64-bit fseek */
+   return _fseeki64(f, offset, origin);
+#elif defined(HAVE_64BIT_OFFSETS)
+   return fseeko(f, (off_t)offset, origin);
+#else
+   return fseek(f, (long)offset, origin);
+#endif
+}
+
+static int64_t ftell_wrap(FILE *f)
+{
+#ifdef ATLEAST_VC2005
+   /* VC2005 and up have a special 64-bit ftell */
+   return _ftelli64(f);
+#elif defined(HAVE_64BIT_OFFSETS)
+   return ftello(f);
+#else
+   return ftell(f);
+#endif
+}
+
+static void *nbio_stdio_open(const char * filename, unsigned mode)
+{
+   void *buf                   = NULL;
+   struct nbio_stdio_t* handle = NULL;
+   int64_t len                 = 0;
+#if !defined(_WIN32) || defined(LEGACY_WIN32)
+   FILE* f                     = fopen(filename, stdio_modes[mode]);
+#else
+   wchar_t *filename_wide      = utf8_to_utf16_string_alloc(filename);
+   FILE* f                     = _wfopen(filename_wide, stdio_modes[mode]);
+
+   if (filename_wide)
+      free(filename_wide);
+#endif
+   if (!f)
+      return NULL;
+
+   handle                = (struct nbio_stdio_t*)malloc(sizeof(struct nbio_stdio_t));
+
+   if (!handle)
+      goto error;
+
+   handle->f             = f;
+
+   switch (mode)
+   {
+      case NBIO_WRITE:
+      case BIO_WRITE:
+         break;
+      default:
+         fseek_wrap(handle->f, 0, SEEK_END);
+         len = ftell_wrap(handle->f);
+         break;
+   }
+
+   handle->mode          = mode;
+
+#if defined(WIIU)
+   /* hit the aligned-buffer fast path on Wii U */
+   if (len)
+      buf                = memalign(0x40, (size_t)len);
+#else
+   if (len)
+      buf                = malloc((size_t)len);
+#endif
+
+   if (len && !buf)
+      goto error;
+
+   handle->data          = buf;
+   handle->len           = len;
+   handle->progress      = handle->len;
+   handle->op            = -2;
+
+   return handle;
+
+error:
+   if (handle)
+      free(handle);
+   fclose(f);
+   return NULL;
+}
+
+static void nbio_stdio_begin_read(void *data)
+{
+   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->op >= 0)
+      abort();
+
+   fseek_wrap(handle->f, 0, SEEK_SET);
+
+   handle->op       = NBIO_READ;
+   handle->progress = 0;
+}
+
+static void nbio_stdio_begin_write(void *data)
+{
+   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->op >= 0)
+      abort();
+
+   fseek_wrap(handle->f, 0, SEEK_SET);
+   handle->op = NBIO_WRITE;
+   handle->progress = 0;
+}
+
+static bool nbio_stdio_iterate(void *data)
+{
+   size_t amount               = 65536;
+   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
+
+   if (!handle)
+      return false;
+
+   if (amount > handle->len - handle->progress)
+      amount = handle->len - handle->progress;
+
+   switch (handle->op)
+   {
+      case NBIO_READ:
+         if (handle->mode == BIO_READ)
+         {
+            amount = handle->len;
+            fread((char*)handle->data, 1, amount, handle->f);
+         }
+         else
+            fread((char*)handle->data + handle->progress, 1, amount, handle->f);
+         break;
+      case NBIO_WRITE:
+         if (handle->mode == BIO_WRITE)
+         {
+            size_t written = 0;
+            amount = handle->len;
+            written = fwrite((char*)handle->data, 1, amount, handle->f);
+            if (written != amount)
+               return false;
+         }
+         else
+            fwrite((char*)handle->data + handle->progress, 1, amount, handle->f);
+         break;
+   }
+
+   handle->progress += amount;
+
+   if (handle->progress == handle->len)
+      handle->op = -1;
+   return (handle->op < 0);
+}
+
+static void nbio_stdio_resize(void *data, size_t len)
+{
+   void *new_data              = NULL;
+   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
+   if (!handle)
+      return;
+
+   if (handle->op >= 0)
+      abort();
+   if (len < handle->len)
+      abort();
+
+   handle->len      = len;
+   handle->progress = len;
+   handle->op       = -1;
+
+   new_data         = realloc(handle->data, handle->len);
+
+   if (new_data)
+      handle->data  = new_data;
+}
+
+static void *nbio_stdio_get_ptr(void *data, size_t* len)
+{
+   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
+   if (!handle)
+      return NULL;
+   if (len)
+      *len = handle->len;
+   if (handle->op == -1)
+      return handle->data;
+   return NULL;
+}
+
+static void nbio_stdio_cancel(void *data)
+{
+   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
+   if (!handle)
+      return;
+
+   handle->op = -1;
+   handle->progress = handle->len;
+}
+
+static void nbio_stdio_free(void *data)
+{
+   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;
+   if (!handle)
+      return;
+   if (handle->op >= 0)
+      abort();
+   fclose(handle->f);
+   free(handle->data);
+
+   handle->f    = NULL;
+   handle->data = NULL;
+   free(handle);
+}
+
+nbio_intf_t nbio_stdio = {
+   nbio_stdio_open,
+   nbio_stdio_begin_read,
+   nbio_stdio_begin_write,
+   nbio_stdio_iterate,
+   nbio_stdio_resize,
+   nbio_stdio_get_ptr,
+   nbio_stdio_cancel,
+   nbio_stdio_free,
+   "nbio_stdio",
+};
diff --git a/deps/libretro-common/file/nbio/nbio_unixmmap.c b/deps/libretro-common/file/nbio/nbio_unixmmap.c
new file mode 100644 (file)
index 0000000..1a94238
--- /dev/null
@@ -0,0 +1,184 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nbio_unixmmap.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <file/nbio.h>
+
+#if defined(HAVE_MMAP) && defined(BSD)
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#ifdef __APPLE__
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0x1000000
+#endif
+
+#else
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+#endif
+
+struct nbio_mmap_unix_t
+{
+   void* ptr;
+   size_t len;
+   int fd;
+   int map_flags;
+};
+
+static void *nbio_mmap_unix_open(const char * filename, unsigned mode)
+{
+   static const int o_flags[] =   { O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC, O_RDWR,               O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC };
+   static const int map_flags[] = { PROT_READ, PROT_WRITE|PROT_READ,   PROT_WRITE|PROT_READ, PROT_READ, PROT_WRITE|PROT_READ   };
+
+   size_t len;
+   void* ptr                       = NULL;
+   struct nbio_mmap_unix_t* handle = NULL;
+   int fd                          = open(filename, o_flags[mode]|O_CLOEXEC, 0644);
+   if (fd < 0)
+      return NULL;
+
+   len = lseek(fd, 0, SEEK_END);
+   if (len != 0)
+      ptr = mmap(NULL, len, map_flags[mode], MAP_SHARED, fd, 0);
+
+   if (ptr == MAP_FAILED)
+   {
+      close(fd);
+      return NULL;
+   }
+
+   handle            = malloc(sizeof(struct nbio_mmap_unix_t));
+   handle->fd        = fd;
+   handle->map_flags = map_flags[mode];
+   handle->len       = len;
+   handle->ptr       = ptr;
+   return handle;
+}
+
+static void nbio_mmap_unix_begin_read(void *data)
+{
+   /* not needed */
+}
+
+static void nbio_mmap_unix_begin_write(void *data)
+{
+   /* not needed */
+}
+
+static bool nbio_mmap_unix_iterate(void *data)
+{
+   return true; /* not needed */
+}
+
+static void nbio_mmap_unix_resize(void *data, size_t len)
+{
+   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
+   if (!handle)
+      return;
+   if (len < handle->len)
+   {
+      /* this works perfectly fine if this check is removed, but it
+       * won't work on other nbio implementations */
+      /* therefore, it's blocked so nobody accidentally relies on it */
+      abort();
+   }
+
+   if (ftruncate(handle->fd, len) != 0)
+      abort(); /* this one returns void and I can't find any other
+                  way for it to report failure */
+
+   munmap(handle->ptr, handle->len);
+
+   handle->ptr = mmap(NULL, len, handle->map_flags, MAP_SHARED, handle->fd, 0);
+   handle->len = len;
+
+   if (handle->ptr == MAP_FAILED)
+      abort();
+}
+
+static void *nbio_mmap_unix_get_ptr(void *data, size_t* len)
+{
+   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
+   if (!handle)
+      return NULL;
+   if (len)
+      *len = handle->len;
+   return handle->ptr;
+}
+
+static void nbio_mmap_unix_cancel(void *data)
+{
+   /* not needed */
+}
+
+static void nbio_mmap_unix_free(void *data)
+{
+   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;
+   if (!handle)
+      return;
+   close(handle->fd);
+   munmap(handle->ptr, handle->len);
+   free(handle);
+}
+
+nbio_intf_t nbio_mmap_unix = {
+   nbio_mmap_unix_open,
+   nbio_mmap_unix_begin_read,
+   nbio_mmap_unix_begin_write,
+   nbio_mmap_unix_iterate,
+   nbio_mmap_unix_resize,
+   nbio_mmap_unix_get_ptr,
+   nbio_mmap_unix_cancel,
+   nbio_mmap_unix_free,
+   "nbio_mmap_unix",
+};
+#else
+nbio_intf_t nbio_mmap_unix = {
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   "nbio_mmap_unix",
+};
+
+#endif
diff --git a/deps/libretro-common/file/nbio/nbio_windowsmmap.c b/deps/libretro-common/file/nbio/nbio_windowsmmap.c
new file mode 100644 (file)
index 0000000..82b1c34
--- /dev/null
@@ -0,0 +1,237 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nbio_windowsmmap.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <file/nbio.h>
+
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1500
+
+#ifndef HAVE_MMAP_WIN32
+#define HAVE_MMAP_WIN32
+#endif
+
+#elif !defined(_MSC_VER)
+
+#ifndef HAVE_MMAP_WIN32
+#define HAVE_MMAP_WIN32
+#endif
+#endif
+
+#endif
+
+#if defined(HAVE_MMAP_WIN32)
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <encodings/utf.h>
+
+#include <windows.h>
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+
+#endif
+
+#ifndef FILE_SHARE_ALL
+#define FILE_SHARE_ALL (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)
+#endif
+
+struct nbio_mmap_win32_t
+{
+   HANDLE file;
+   void* ptr;
+   size_t len;
+   bool is_write;
+};
+
+static void *nbio_mmap_win32_open(const char * filename, unsigned mode)
+{
+   static const DWORD dispositions[] = { OPEN_EXISTING, CREATE_ALWAYS, OPEN_ALWAYS, OPEN_EXISTING, CREATE_ALWAYS };
+   HANDLE mem;
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
+   LARGE_INTEGER len;
+#else
+   SIZE_T len;
+#endif
+   struct nbio_mmap_win32_t* handle  = NULL;
+   void* ptr                         = NULL;
+   bool is_write                     = (mode == NBIO_WRITE || mode == NBIO_UPDATE || mode == BIO_WRITE);
+   DWORD access                      = (is_write ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ);
+#if !defined(_WIN32) || defined(LEGACY_WIN32)
+   HANDLE file                       = CreateFile(filename, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
+#else
+   wchar_t *filename_wide            = utf8_to_utf16_string_alloc(filename);
+#ifdef __WINRT__
+   HANDLE file                       = CreateFile2(filename_wide, access, FILE_SHARE_ALL, dispositions[mode], NULL);
+#else
+   HANDLE file                       = CreateFileW(filename_wide, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
+#endif
+
+   if (filename_wide)
+      free(filename_wide);
+#endif
+
+   if (file == INVALID_HANDLE_VALUE)
+      return NULL;
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
+   /* GetFileSizeEx is new for Windows 2000 */
+   GetFileSizeEx(file, &len);
+   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
+   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len.QuadPart);
+#else
+   GetFileSize(file, &len);
+   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
+   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
+#endif
+
+   CloseHandle(mem);
+
+   handle           = (struct nbio_mmap_win32_t*)malloc(sizeof(struct nbio_mmap_win32_t));
+
+   handle->file     = file;
+   handle->is_write = is_write;
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
+   handle->len      = len.QuadPart;
+#else
+   handle->len      = len;
+#endif
+   handle->ptr      = ptr;
+
+   return handle;
+}
+
+static void nbio_mmap_win32_begin_read(void *data)
+{
+   /* not needed */
+}
+
+static void nbio_mmap_win32_begin_write(void *data)
+{
+   /* not needed */
+}
+
+static bool nbio_mmap_win32_iterate(void *data)
+{
+   /* not needed */
+   return true;
+}
+
+static void nbio_mmap_win32_resize(void *data, size_t len)
+{
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
+   LARGE_INTEGER len_li;
+#else
+   SIZE_T len_li;
+#endif
+   HANDLE mem;
+   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;
+
+   if (!handle)
+      return;
+
+   if (len < handle->len)
+   {
+      /* this works perfectly fine if this check is removed,
+       * but it won't work on other nbio implementations */
+      /* therefore, it's blocked so nobody accidentally
+       * relies on it. */
+      abort();
+   }
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
+   /* SetFilePointerEx is new for Windows 2000 */
+   len_li.QuadPart = len;
+   SetFilePointerEx(handle->file, len_li, NULL, FILE_BEGIN);
+#else
+   len_li = len;
+   SetFilePointer(handle->file, len_li, NULL, FILE_BEGIN);
+#endif
+
+   if (!SetEndOfFile(handle->file))
+      abort(); /* this one returns void and I can't find any other way for it to report failure */
+   handle->len = len;
+
+   UnmapViewOfFile(handle->ptr);
+   mem = CreateFileMapping(handle->file, NULL, handle->is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
+   handle->ptr = MapViewOfFile(mem, handle->is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
+   CloseHandle(mem);
+
+   if (!handle->ptr)
+      abort();
+}
+
+static void *nbio_mmap_win32_get_ptr(void *data, size_t* len)
+{
+   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;
+   if (!handle)
+      return NULL;
+   if (len)
+      *len = handle->len;
+   return handle->ptr;
+}
+
+static void nbio_mmap_win32_cancel(void *data)
+{
+   /* not needed */
+}
+
+static void nbio_mmap_win32_free(void *data)
+{
+   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;
+   if (!handle)
+      return;
+   CloseHandle(handle->file);
+   UnmapViewOfFile(handle->ptr);
+   free(handle);
+}
+
+nbio_intf_t nbio_mmap_win32 = {
+   nbio_mmap_win32_open,
+   nbio_mmap_win32_begin_read,
+   nbio_mmap_win32_begin_write,
+   nbio_mmap_win32_iterate,
+   nbio_mmap_win32_resize,
+   nbio_mmap_win32_get_ptr,
+   nbio_mmap_win32_cancel,
+   nbio_mmap_win32_free,
+   "nbio_mmap_win32",
+};
+#else
+nbio_intf_t nbio_mmap_win32 = {
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+   "nbio_mmap_win32",
+};
+
+#endif
diff --git a/deps/libretro-common/file/retro_dirent.c b/deps/libretro-common/file/retro_dirent.c
new file mode 100644 (file)
index 0000000..51f89c2
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_dirent.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_common.h>
+
+#include <boolean.h>
+#include <retro_dirent.h>
+#define VFS_FRONTEND
+#include <vfs/vfs_implementation.h>
+
+/* TODO/FIXME - static globals */
+static retro_vfs_opendir_t dirent_opendir_cb                 = NULL;
+static retro_vfs_readdir_t dirent_readdir_cb                 = NULL;
+static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
+static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb     = NULL;
+static retro_vfs_closedir_t dirent_closedir_cb               = NULL;
+
+void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
+{
+   const struct retro_vfs_interface* vfs_iface;
+
+   dirent_opendir_cb         = NULL;
+   dirent_readdir_cb         = NULL;
+   dirent_dirent_get_name_cb = NULL;
+   dirent_dirent_is_dir_cb   = NULL;
+   dirent_closedir_cb        = NULL;
+
+   vfs_iface                 = vfs_info->iface;
+
+   if (
+         vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION || 
+         !vfs_iface)
+      return;
+
+   dirent_opendir_cb         = vfs_iface->opendir;
+   dirent_readdir_cb         = vfs_iface->readdir;
+   dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;
+   dirent_dirent_is_dir_cb   = vfs_iface->dirent_is_dir;
+   dirent_closedir_cb        = vfs_iface->closedir;
+}
+
+struct RDIR *retro_opendir_include_hidden(
+      const char *name, bool include_hidden)
+{
+   if (dirent_opendir_cb)
+      return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
+   return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
+}
+
+struct RDIR *retro_opendir(const char *name)
+{
+   return retro_opendir_include_hidden(name, false);
+}
+
+bool retro_dirent_error(struct RDIR *rdir)
+{
+   /* Left for compatibility */
+   return false;
+}
+
+int retro_readdir(struct RDIR *rdir)
+{
+   if (dirent_readdir_cb)
+      return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
+   return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
+}
+
+const char *retro_dirent_get_name(struct RDIR *rdir)
+{
+   if (dirent_dirent_get_name_cb)
+      return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
+   return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
+}
+
+/**
+ *
+ * retro_dirent_is_dir:
+ * @rdir         : pointer to the directory entry.
+ * @unused       : deprecated, included for compatibility reasons, pass NULL
+ *
+ * Is the directory listing entry a directory?
+ *
+ * Returns: true if directory listing entry is
+ * a directory, false if not.
+ */
+bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
+{
+   if (dirent_dirent_is_dir_cb)
+      return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
+   return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
+}
+
+void retro_closedir(struct RDIR *rdir)
+{
+   if (dirent_closedir_cb)
+      dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
+   else
+      retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);
+}
diff --git a/deps/libretro-common/formats/bmp/rbmp.c b/deps/libretro-common/formats/bmp/rbmp.c
new file mode 100644 (file)
index 0000000..1d3f489
--- /dev/null
@@ -0,0 +1,785 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rbmp.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* Modified version of stb_image's BMP sources. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stddef.h> /* ptrdiff_t on osx */
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_inline.h>
+
+#include <formats/image.h>
+#include <formats/rbmp.h>
+
+/* truncate int to byte without warnings */
+#define RBMP_BYTECAST(x)  ((unsigned char) ((x) & 255))
+
+#define RBMP_COMPUTE_Y(r, g, b) ((unsigned char) ((((r) * 77) + ((g) * 150) +  (29 * (b))) >> 8))
+
+typedef struct
+{
+   unsigned char *img_buffer;
+   unsigned char *img_buffer_end;
+   unsigned char *img_buffer_original;
+   int img_n;
+   int img_out_n;
+   int buflen;
+   uint32_t img_x;
+   uint32_t img_y;
+   unsigned char buffer_start[128];
+} rbmp_context;
+
+struct rbmp
+{
+   uint8_t *buff_data;
+   uint32_t *output_image;
+};
+
+static INLINE unsigned char rbmp_get8(rbmp_context *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+
+   return 0;
+}
+
+static void rbmp_skip(rbmp_context *s, int n)
+{
+   if (n < 0)
+   {
+      s->img_buffer = s->img_buffer_end;
+      return;
+   }
+
+   s->img_buffer += n;
+}
+
+static int rbmp_get16le(rbmp_context *s)
+{
+   return rbmp_get8(s) + (rbmp_get8(s) << 8);
+}
+
+#define RBMP_GET32LE(s) (rbmp_get16le(s) + (rbmp_get16le(s) << 16))
+
+static unsigned char *rbmp_convert_format(
+      unsigned char *data,
+      int img_n,
+      int req_comp,
+      unsigned int x,
+      unsigned int y)
+{
+   int i,j;
+   unsigned char *good = (unsigned char *)malloc(req_comp * x * y);
+
+   if (!good)
+      return NULL;
+
+   for (j=0; j < (int) y; ++j)
+   {
+      unsigned char *src  = data + j * x * img_n   ;
+      unsigned char *dest = good + j * x * req_comp;
+
+      switch (((img_n)*8+(req_comp)))
+      {
+         case 10:
+            for (i = x-1; i >= 0; --i, src += 1, dest += 2)
+            {
+               dest[0]=src[0];
+               dest[1]=255;
+            }
+            break;
+         case 11:
+            for (i = x-1; i >= 0; --i, src += 1, dest += 3)
+               dest[0]=dest[1]=dest[2]=src[0];
+            break;
+         case 12:
+            for (i = x-1; i >= 0; --i, src += 1, dest += 4)
+            {
+               dest[0]=dest[1]=dest[2]=src[0];
+               dest[3]=255;
+            }
+            break;
+         case 17:
+            for (i = x-1; i >= 0; --i, src += 2, dest += 1)
+               dest[0]=src[0];
+            break;
+         case 19:
+            for (i = x-1; i >= 0; --i, src += 2, dest += 3)
+               dest[0]=dest[1]=dest[2]=src[0];
+            break;
+         case 20:
+            for (i = x-1; i >= 0; --i, src += 2, dest += 4)
+            {
+               dest[0]=dest[1]=dest[2]=src[0];
+               dest[3]=src[1];
+            }
+            break;
+         case 28:
+            for (i = x-1; i >= 0; --i, src += 3, dest += 4)
+            {
+               dest[0]=src[0];
+               dest[1]=src[1];
+               dest[2]=src[2];
+               dest[3]=255;
+            }
+            break;
+         case 25:
+            for (i = x-1; i >= 0; --i, src += 3, dest += 1)
+               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
+            break;
+         case 26:
+            for (i = x-1; i >= 0; --i, src += 3, dest += 2)
+            {
+               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
+               dest[1] = 255;
+            }
+            break;
+         case 33:
+            for (i = x-1; i >= 0; --i, src += 4, dest += 1)
+               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
+            break;
+         case 34:
+            for (i = x-1; i >= 0; --i, src += 4, dest += 2)
+            {
+               dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
+               dest[1] = src[3];
+            }
+            break;
+         case 35:
+            for (i = x-1; i >= 0; --i, src += 4, dest += 3)
+            {
+               dest[0]=src[0];
+               dest[1]=src[1];
+               dest[2]=src[2];
+            }
+            break;
+         default:
+            break;
+      }
+
+   }
+
+   return good;
+}
+
+/* Microsoft/Windows BMP image */
+
+/* returns 0..31 for the highest set bit */
+static int rbmp_high_bit(unsigned int z)
+{
+   int n=0;
+   if (z == 0)
+      return -1;
+
+   if (z >= 0x10000)
+   {
+      n  += 16;
+      z >>= 16;
+   }
+   if (z >= 0x00100)
+   {
+      n  +=  8;
+      z >>=  8;
+   }
+   if (z >= 0x00010)
+   {
+      n  +=  4;
+      z >>=  4;
+   }
+   if (z >= 0x00004)
+   {
+      n  +=  2;
+      z >>=  2;
+   }
+   if (z >= 0x00002)
+      n +=  1;
+   return n;
+}
+
+static int rbmp_bitcount(unsigned int a)
+{
+   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); /* max 2 */
+   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); /* max 4 */
+   a = (a + (a >> 4)) & 0x0f0f0f0f; /* max 8 per 4, now 8 bits */
+   a = (a + (a >> 8));              /* max 16 per 8 bits */
+   a = (a + (a >> 16));             /* max 32 per 8 bits */
+   return a & 0xff;
+}
+
+static int rbmp_shiftsigned(int v, int shift, int bits)
+{
+   int result;
+   int z = bits;
+
+   if (shift < 0)
+      v <<= -shift;
+   else
+      v >>= shift;
+
+   result = v;
+
+   while (z < 8)
+   {
+      result += v >> z;
+      z      += bits;
+   }
+   return result;
+}
+
+static unsigned char *rbmp_bmp_load(rbmp_context *s, unsigned *x, unsigned *y,
+      int *comp, int req_comp)
+{
+   unsigned char *out;
+   int bpp, flip_vertically, pad, target, offset, hsz;
+   int psize=0,i,j,width;
+   unsigned int mr=0,mg=0,mb=0,ma=0;
+
+   /* Corrupt BMP? */
+   if (rbmp_get8(s) != 'B' || rbmp_get8(s) != 'M')
+      return 0;
+
+   /* discard filesize */
+   rbmp_get16le(s);
+   rbmp_get16le(s);
+   /* discard reserved */
+   rbmp_get16le(s);
+   rbmp_get16le(s);
+
+   offset = (uint32_t)RBMP_GET32LE(s);
+   hsz    = (uint32_t)RBMP_GET32LE(s);
+
+   /* BMP type not supported? */
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)
+      return 0;
+
+   if (hsz == 12)
+   {
+      s->img_x = rbmp_get16le(s);
+      s->img_y = rbmp_get16le(s);
+   }
+   else
+   {
+      s->img_x = (uint32_t)RBMP_GET32LE(s);
+      s->img_y = (uint32_t)RBMP_GET32LE(s);
+   }
+
+   /* Bad BMP? */
+   if (rbmp_get16le(s) != 1)
+      return 0;
+
+   bpp = rbmp_get16le(s);
+
+   /* BMP 1-bit type not supported? */
+   if (bpp == 1)
+      return 0;
+
+   flip_vertically = ((int) s->img_y) > 0;
+   s->img_y        = abs((int) s->img_y);
+
+   if (hsz == 12)
+   {
+      if (bpp < 24)
+         psize = (offset - 14 - 24) / 3;
+   }
+   else
+   {
+      int compress = (uint32_t)RBMP_GET32LE(s);
+
+      /* BMP RLE type not supported? */
+      if (compress == 1 || compress == 2)
+         return 0;
+
+      /* discard sizeof */
+      rbmp_get16le(s);
+      rbmp_get16le(s);
+      /* discard hres */
+      rbmp_get16le(s);
+      rbmp_get16le(s);
+      /* discard vres */
+      rbmp_get16le(s);
+      rbmp_get16le(s);
+      /* discard colors used */
+      rbmp_get16le(s);
+      rbmp_get16le(s);
+      /* discard max important */
+      rbmp_get16le(s);
+      rbmp_get16le(s);
+
+      if (hsz == 40 || hsz == 56)
+      {
+         if (hsz == 56)
+         {
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+         }
+         if (bpp == 16 || bpp == 32)
+         {
+            switch (compress)
+            {
+               case 0:
+#if 0
+                  if (bpp == 32)
+                  {
+                     mr = 0xffu << 16;
+                     mg = 0xffu <<  8;
+                     mb = 0xffu <<  0;
+                     ma = 0xffu << 24;
+                  }
+                  else
+                  {
+                     mr = 31u << 10;
+                     mg = 31u <<  5;
+                     mb = 31u <<  0;
+                  }
+#endif
+                  break;
+               case 3:
+                  mr = (uint32_t)RBMP_GET32LE(s);
+                  mg = (uint32_t)RBMP_GET32LE(s);
+                  mb = (uint32_t)RBMP_GET32LE(s);
+                  /* not documented, but generated by
+                   * Photoshop and handled by MS Paint */
+                  /* Bad BMP ?*/
+                  if (mr == mg && mg == mb)
+                     return 0;
+                  break;
+               default:
+#if 0
+                  mr = mg = mb = 0;
+#endif
+                  break;
+            }
+
+            /* Bad BMP? */
+            return 0;
+         }
+      }
+      else
+      {
+         mr = (uint32_t)RBMP_GET32LE(s);
+         mg = (uint32_t)RBMP_GET32LE(s);
+         mb = (uint32_t)RBMP_GET32LE(s);
+         ma = (uint32_t)RBMP_GET32LE(s);
+         /* Discard color space */
+         rbmp_get16le(s);
+         rbmp_get16le(s);
+         for (i = 0; i < 12; ++i)
+         {
+            /* Discard color space parameters */
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+         }
+         if (hsz == 124)
+         {
+            /* Discard rendering intent */
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            /* Discard offset of profile data */
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            /* Discard size of profile data */
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+            /* Discard reserved */
+            rbmp_get16le(s);
+            rbmp_get16le(s);
+         }
+      }
+      if (bpp < 16)
+         psize = (offset - 14 - hsz) >> 2;
+   }
+   s->img_n = ma ? 4 : 3;
+   if (req_comp && req_comp >= 3) /* We can directly decode 3 or 4 */
+      target = req_comp;
+   else
+      target = s->img_n; /* If they want monochrome, we'll post-convert */
+
+   out = (unsigned char *) malloc(target * s->img_x * s->img_y);
+
+   if (!out)
+      return 0;
+
+   if (bpp < 16)
+   {
+      unsigned char pal[256][4];
+      int z=0;
+
+      /* Corrupt BMP? */
+      if (psize == 0 || psize > 256)
+      {
+         free(out);
+         return 0;
+      }
+
+      for (i = 0; i < psize; ++i)
+      {
+         pal[i][2] = rbmp_get8(s);
+         pal[i][1] = rbmp_get8(s);
+         pal[i][0] = rbmp_get8(s);
+         if (hsz != 12)
+            rbmp_get8(s);
+         pal[i][3] = 255;
+      }
+
+      rbmp_skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
+      if (bpp == 4)
+         width = (s->img_x + 1) >> 1;
+      else if (bpp == 8)
+         width = s->img_x;
+      else
+      {
+         /* Corrupt BMP */
+         free(out);
+         return 0;
+      }
+
+      pad = (-width)&3;
+      for (j=0; j < (int) s->img_y; ++j)
+      {
+         for (i = 0; i < (int) s->img_x; i += 2)
+         {
+            int v  = rbmp_get8(s);
+            int v2 = 0;
+            if (bpp == 4)
+            {
+               v2  = v & 15;
+               v >>= 4;
+            }
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+            if (target == 4)
+               out[z++] = 255;
+
+            if (i+1 == (int)s->img_x)
+               break;
+
+            v        = (bpp == 8) ? rbmp_get8(s) : v2;
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+
+            if (target == 4)
+               out[z++] = 255;
+         }
+         rbmp_skip(s, pad);
+      }
+   }
+   else
+   {
+      int rshift = 0;
+      int gshift = 0;
+      int bshift = 0;
+      int ashift = 0;
+      int rcount = 0;
+      int gcount = 0;
+      int bcount = 0;
+      int acount = 0;
+      int z      = 0;
+      int easy   = 0;
+
+      rbmp_skip(s, offset - 14 - hsz);
+
+      if (bpp == 24)
+         width = 3 * s->img_x;
+      else if (bpp == 16)
+         width = 2*s->img_x;
+      else /* bpp = 32 and pad = 0 */
+         width=0;
+
+      pad = (-width) & 3;
+
+      switch (bpp)
+      {
+         case 24:
+            easy = 1;
+            break;
+         case 32:
+            if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+               easy = 2;
+            break;
+         default:
+            break;
+      }
+
+      if (!easy)
+      {
+         /* Corrupt BMP? */
+         if (!mr || !mg || !mb)
+         {
+            free(out);
+            return 0;
+         }
+
+         /* right shift amt to put high bit in position #7 */
+         rshift = rbmp_high_bit(mr)-7;
+         rcount = rbmp_bitcount(mr);
+         gshift = rbmp_high_bit(mg)-7;
+         gcount = rbmp_bitcount(mg);
+         bshift = rbmp_high_bit(mb)-7;
+         bcount = rbmp_bitcount(mb);
+         ashift = rbmp_high_bit(ma)-7;
+         acount = rbmp_bitcount(ma);
+      }
+
+      for (j=0; j < (int) s->img_y; ++j)
+      {
+         if (easy)
+         {
+            if (target == 4)
+            {
+               /* Need to apply alpha channel as well */
+               if (easy == 2)
+               {
+                  for (i = 0; i < (int) s->img_x; ++i)
+                  {
+                     out[z+2]        = rbmp_get8(s);
+                     out[z+1]        = rbmp_get8(s);
+                     out[z+0]        = rbmp_get8(s);
+                     z              += 3;
+                     out[z++]        = rbmp_get8(s);
+                  }
+               }
+               else
+               {
+                  for (i = 0; i < (int) s->img_x; ++i)
+                  {
+                     out[z+2]        = rbmp_get8(s);
+                     out[z+1]        = rbmp_get8(s);
+                     out[z+0]        = rbmp_get8(s);
+                     z              += 3;
+                     out[z++]        = 255;
+                  }
+               }
+            }
+            else
+            {
+               for (i = 0; i < (int) s->img_x; ++i)
+               {
+                  out[z+2]        = rbmp_get8(s);
+                  out[z+1]        = rbmp_get8(s);
+                  out[z+0]        = rbmp_get8(s);
+                  z              += 3;
+               }
+            }
+         }
+         else
+         {
+            if (target == 4)
+            {
+               /* Need to apply alpha channel as well */
+               if (ma)
+               {
+                  if (bpp == 16)
+                  {
+                     for (i = 0; i < (int) s->img_x; ++i)
+                     {
+                        uint32_t v  = (uint32_t)rbmp_get16le(s);
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & ma, ashift, acount));
+                     }
+                  }
+                  else
+                  {
+                     for (i = 0; i < (int) s->img_x; ++i)
+                     {
+                        uint32_t v  = (uint32_t)RBMP_GET32LE(s);
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & ma, ashift, acount));
+                     }
+                  }
+               }
+               else
+               {
+                  if (bpp == 16)
+                  {
+                     for (i = 0; i < (int) s->img_x; ++i)
+                     {
+                        uint32_t v  = (uint32_t)rbmp_get16le(s);
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
+                        out[z++]    = RBMP_BYTECAST(255);
+                     }
+                  }
+                  else
+                  {
+                     for (i = 0; i < (int) s->img_x; ++i)
+                     {
+                        uint32_t v  = (uint32_t)RBMP_GET32LE(s);
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
+                        out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
+                        out[z++]    = RBMP_BYTECAST(255);
+                     }
+                  }
+               }
+            }
+            else
+            {
+               if (bpp == 16)
+               {
+                  for (i = 0; i < (int) s->img_x; ++i)
+                  {
+                     uint32_t v  = (uint32_t)rbmp_get16le(s);
+                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
+                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
+                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
+                  }
+               }
+               else
+               {
+                  for (i = 0; i < (int) s->img_x; ++i)
+                  {
+                     uint32_t v  = (uint32_t)RBMP_GET32LE(s);
+                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));
+                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));
+                     out[z++]    = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));
+                  }
+               }
+            }
+         }
+         rbmp_skip(s, pad);
+      }
+   }
+
+   if (flip_vertically)
+   {
+      unsigned char t;
+      for (j=0; j < (int) s->img_y>>1; ++j)
+      {
+         unsigned char *p1 = out +      j     *s->img_x*target;
+         unsigned char *p2 = out + (s->img_y-1-j)*s->img_x*target;
+         for (i = 0; i < (int) s->img_x*target; ++i)
+         {
+            t     = p1[i];
+            p1[i] = p2[i];
+            p2[i] = t;
+         }
+      }
+   }
+
+   if (
+            req_comp
+         && (req_comp >= 1 && req_comp <= 4)
+         && (req_comp != target))
+   {
+      unsigned char *tmp = rbmp_convert_format(out, target, req_comp, s->img_x, s->img_y);
+
+      free(out);
+      out = NULL;
+
+      if (!tmp)
+         return NULL;
+
+      out = tmp;
+   }
+
+   *x = s->img_x;
+   *y = s->img_y;
+
+   if (comp)
+      *comp = s->img_n;
+
+   return out;
+}
+
+static unsigned char *rbmp_load_from_memory(unsigned char const *buffer, int len,
+      unsigned *x, unsigned *y, int *comp, int req_comp)
+{
+   rbmp_context s;
+
+   s.img_buffer          = (unsigned char*)buffer;
+   s.img_buffer_original = (unsigned char*)buffer;
+   s.img_buffer_end      = (unsigned char*)buffer+len;
+
+   return rbmp_bmp_load(&s,x,y,comp,req_comp);
+}
+
+static void rbmp_convert_frame(uint32_t *frame, unsigned width, unsigned height)
+{
+   uint32_t *end = frame + (width * height * sizeof(uint32_t))/4;
+
+   while (frame < end)
+   {
+      uint32_t pixel = *frame;
+      *frame = (pixel & 0xff00ff00) | ((pixel << 16) & 0x00ff0000) | ((pixel >> 16) & 0xff);
+      frame++;
+   }
+}
+
+int rbmp_process_image(rbmp_t *rbmp, void **buf_data,
+      size_t size, unsigned *width, unsigned *height)
+{
+   int comp;
+
+   if (!rbmp)
+      return IMAGE_PROCESS_ERROR;
+
+   rbmp->output_image   = (uint32_t*)rbmp_load_from_memory(rbmp->buff_data,
+                           (int)size, width, height, &comp, 4);
+   *buf_data             = rbmp->output_image;
+
+   rbmp_convert_frame(rbmp->output_image, *width, *height);
+
+   return IMAGE_PROCESS_END;
+}
+
+bool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data)
+{
+   if (!rbmp)
+      return false;
+
+   rbmp->buff_data = (uint8_t*)data;
+
+   return true;
+}
+
+void rbmp_free(rbmp_t *rbmp)
+{
+   if (!rbmp)
+      return;
+
+   free(rbmp);
+}
+
+rbmp_t *rbmp_alloc(void)
+{
+   rbmp_t *rbmp = (rbmp_t*)calloc(1, sizeof(*rbmp));
+   if (!rbmp)
+      return NULL;
+   return rbmp;
+}
diff --git a/deps/libretro-common/formats/bmp/rbmp_encode.c b/deps/libretro-common/formats/bmp/rbmp_encode.c
new file mode 100644 (file)
index 0000000..0cf619d
--- /dev/null
@@ -0,0 +1,236 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rbmp_encode.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <streams/file_stream.h>
+#include <formats/rbmp.h>
+
+void form_bmp_header(uint8_t *header,
+      unsigned width, unsigned height,
+      bool is32bpp)
+{
+   unsigned line_size  = (width * (is32bpp?4:3) + 3) & ~3;
+   unsigned size       = line_size * height + 54;
+   unsigned size_array = line_size * height;
+
+   /* Generic BMP stuff. */
+   /* signature */
+   header[0] = 'B';
+   header[1] = 'M';
+   /* file size */
+   header[2] = (uint8_t)(size >> 0);
+   header[3] = (uint8_t)(size >> 8);
+   header[4] = (uint8_t)(size >> 16);
+   header[5] = (uint8_t)(size >> 24);
+   /* reserved */
+   header[6] = 0;
+   header[7] = 0;
+   header[8] = 0;
+   header[9] = 0;
+   /* offset */
+   header[10] = 54;
+   header[11] = 0;
+   header[12] = 0;
+   header[13] = 0;
+   /* DIB size */
+   header[14] = 40;
+   header[15] = 0;
+   header[16] = 0;
+   header[17] = 0;
+   /* Width */
+   header[18] = (uint8_t)(width >> 0);
+   header[19] = (uint8_t)(width >> 8);
+   header[20] = (uint8_t)(width >> 16);
+   header[21] = (uint8_t)(width >> 24);
+   /* Height */
+   header[22] = (uint8_t)(height >> 0);
+   header[23] = (uint8_t)(height >> 8);
+   header[24] = (uint8_t)(height >> 16);
+   header[25] = (uint8_t)(height >> 24);
+   /* Color planes */
+   header[26] = 1;
+   header[27] = 0;
+   /* Bits per pixel */
+   header[28] = is32bpp ? 32 : 24;
+   header[29] = 0;
+   /* Compression method */
+   header[30] = 0;
+   header[31] = 0;
+   header[32] = 0;
+   header[33] = 0;
+   /* Image data size */
+   header[34] = (uint8_t)(size_array >> 0);
+   header[35] = (uint8_t)(size_array >> 8);
+   header[36] = (uint8_t)(size_array >> 16);
+   header[37] = (uint8_t)(size_array >> 24);
+   /* Horizontal resolution */
+   header[38] = 19;
+   header[39] = 11;
+   header[40] = 0;
+   header[41] = 0;
+   /* Vertical resolution */
+   header[42] = 19;
+   header[43] = 11;
+   header[44] = 0;
+   header[45] = 0;
+   /* Palette size */
+   header[46] = 0;
+   header[47] = 0;
+   header[48] = 0;
+   header[49] = 0;
+   /* Important color count */
+   header[50] = 0;
+   header[51] = 0;
+   header[52] = 0;
+   header[53] = 0;
+}
+
+static bool write_header_bmp(RFILE *file, unsigned width, unsigned height, bool is32bpp)
+{
+   uint8_t header[54];
+   form_bmp_header(header, width, height, is32bpp);
+   return filestream_write(file, header, sizeof(header)) == sizeof(header);
+}
+
+static void dump_line_565_to_24(uint8_t *line, const uint16_t *src, unsigned width)
+{
+   unsigned i;
+
+   for (i = 0; i < width; i++)
+   {
+      uint16_t pixel = *src++;
+      uint8_t b = (pixel >>  0) & 0x1f;
+      uint8_t g = (pixel >>  5) & 0x3f;
+      uint8_t r = (pixel >> 11) & 0x1f;
+      *line++   = (b << 3) | (b >> 2);
+      *line++   = (g << 2) | (g >> 4);
+      *line++   = (r << 3) | (r >> 2);
+   }
+}
+
+static void dump_line_32_to_24(uint8_t *line, const uint32_t *src, unsigned width)
+{
+   unsigned i;
+
+   for (i = 0; i < width; i++)
+   {
+      uint32_t pixel = *src++;
+      *line++ = (pixel >>  0) & 0xff;
+      *line++ = (pixel >>  8) & 0xff;
+      *line++ = (pixel >> 16) & 0xff;
+   }
+}
+
+static void dump_content(RFILE *file, const void *frame,
+      int width, int height, int pitch, enum rbmp_source_type type)
+{
+   int j;
+   size_t line_size;
+   uint8_t *line       = NULL;
+   int bytes_per_pixel = (type==RBMP_SOURCE_TYPE_ARGB8888?4:3);
+   union
+   {
+      const uint8_t *u8;
+      const uint16_t *u16;
+      const uint32_t *u32;
+   } u;
+
+   u.u8      = (const uint8_t*)frame;
+   line_size = (width * bytes_per_pixel + 3) & ~3;
+
+   switch (type)
+   {
+      case RBMP_SOURCE_TYPE_BGR24:
+         {
+            /* BGR24 byte order input matches output. Can directly copy, but... need to make sure we pad it. */
+            uint32_t zeros = 0;
+            int padding    = (int)(line_size-pitch);
+            for (j = 0; j < height; j++, u.u8 += pitch)
+            {
+               filestream_write(file, u.u8, pitch);
+               if (padding != 0)
+                  filestream_write(file, &zeros, padding);
+            }
+         }
+         break;
+      case RBMP_SOURCE_TYPE_ARGB8888:
+         /* ARGB8888 byte order input matches output. Can directly copy. */
+         for (j = 0; j < height; j++, u.u8 += pitch)
+            filestream_write(file, u.u8, line_size);
+         return;
+      default:
+         break;
+   }
+
+   /* allocate line buffer, and initialize the final four bytes to zero, for deterministic padding */
+   if (!(line = (uint8_t*)malloc(line_size)))
+      return;
+   *(uint32_t*)(line + line_size - 4) = 0;
+
+   switch (type)
+   {
+      case RBMP_SOURCE_TYPE_XRGB888:
+         for (j = 0; j < height; j++, u.u8 += pitch)
+         {
+            dump_line_32_to_24(line, u.u32, width);
+            filestream_write(file, line, line_size);
+         }
+         break;
+      case RBMP_SOURCE_TYPE_RGB565:
+         for (j = 0; j < height; j++, u.u8 += pitch)
+         {
+            dump_line_565_to_24(line, u.u16, width);
+            filestream_write(file, line, line_size);
+         }
+         break;
+      default:
+         break;
+   }
+
+   /* Free allocated line buffer */
+   free(line);
+}
+
+bool rbmp_save_image(
+      const char *filename,
+      const void *frame,
+      unsigned width, unsigned height,
+      unsigned pitch, enum rbmp_source_type type)
+{
+   bool ret    = false;
+   RFILE *file = filestream_open(filename,
+         RETRO_VFS_FILE_ACCESS_WRITE,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   if (!file)
+      return false;
+
+   ret = write_header_bmp(file, width, height, type==RBMP_SOURCE_TYPE_ARGB8888);
+
+   if (ret)
+      dump_content(file, frame, width, height, pitch, type);
+
+   filestream_close(file);
+
+   return ret;
+}
diff --git a/deps/libretro-common/formats/cdfs/cdfs.c b/deps/libretro-common/formats/cdfs/cdfs.c
new file mode 100644 (file)
index 0000000..20cbf14
--- /dev/null
@@ -0,0 +1,669 @@
+#include <formats/cdfs.h>
+
+#include <retro_miscellaneous.h>
+#include <compat/strl.h>
+#include <file/file_path.h>
+#include <string/stdstring.h>
+
+#ifdef HAVE_CHD
+#include <streams/chd_stream.h>
+#endif
+
+static void cdfs_determine_sector_size(cdfs_track_t* track)
+{
+   uint8_t buffer[32];
+   const int toc_sector = 16;
+
+   /* MODE information is normally found in the CUE sheet, but we can try to determine it from the raw data.
+    *
+    *   MODE1/2048 - CDROM Mode1 Data (cooked) [no header, no footer]
+    *   MODE1/2352 - CDROM Mode1 Data (raw)    [16 byte header, 288 byte footer]
+    *   MODE2/2336 - CDROM-XA Mode2 Data       [8 byte header, 280 byte footer]
+    *   MODE2/2352 - CDROM-XA Mode2 Data       [24 byte header, 280 byte footer]
+    *
+    * Note that MODE is actually a property on each sector and can change between 1 and 2 depending on how much error
+    * correction the author desired. To support that, the data format must be "/2352" to include the full header and
+    * data without error correction information, at which point the CUE sheet information becomes just a hint.
+    */
+
+   /* The boot record or primary volume descriptor is always at sector 16 and will contain a "CD001" marker */
+   intfstream_seek(track->stream, toc_sector * 2352 + track->first_sector_offset, SEEK_SET);
+   if (intfstream_read(track->stream, &buffer, sizeof(buffer)) != (int64_t)sizeof(buffer))
+      return;
+
+   /* if this is a CDROM-XA data source, the "CD001" tag will be 25 bytes into the sector */
+   if (  buffer[25] == 0x43 
+      && buffer[26] == 0x44
+      && buffer[27] == 0x30 
+      && buffer[28] == 0x30 
+      && buffer[29] == 0x31)
+   {
+      track->stream_sector_size        = 2352;
+      track->stream_sector_header_size = 24;
+   }
+   /* otherwise it should be 17 bytes into the sector */
+   else if (buffer[17] == 0x43
+      &&    buffer[18] == 0x44
+      &&    buffer[19] == 0x30 
+      &&    buffer[20] == 0x30 
+      &&    buffer[21] == 0x31)
+   {
+      track->stream_sector_size = 2352;
+      track->stream_sector_header_size = 16;
+   }
+   else
+   {
+      /* ISO-9660 says the first twelve bytes of a sector should be the sync pattern 00 FF FF FF FF FF FF FF FF FF FF 00 */
+      if (
+            buffer[ 0] == 0
+         && buffer[ 1] == 0xFF
+         && buffer[ 2] == 0xFF
+         && buffer[ 3] == 0xFF
+         && buffer[ 4] == 0xFF
+         && buffer[ 5] == 0xFF
+         && buffer[ 6] == 0xFF
+         && buffer[ 7] == 0xFF
+         && buffer[ 8] == 0xFF
+         && buffer[ 9] == 0xFF
+         && buffer[10] == 0xFF 
+         && buffer[11] == 0)
+      {
+         /* if we didn't find a CD001 tag, this format may predate ISO-9660 */
+
+         /* after the 12 byte sync pattern is three bytes identifying the sector and then one byte for the mode (total 16 bytes) */
+         track->stream_sector_size        = 2352;
+         track->stream_sector_header_size = 16;
+      }
+   }
+}
+
+static void cdfs_determine_sector_size_from_file_size(cdfs_track_t* track)
+{
+   /* attempt to determine stream_sector_size from file size */
+   size_t size = intfstream_get_size(track->stream);
+
+   if ((size % 2352) == 0)
+   {
+      /* raw tracks use all 2352 bytes and have a 24 byte header */
+      track->stream_sector_size        = 2352;
+      track->stream_sector_header_size = 24;
+   }
+   else if ((size % 2048) == 0)
+   {
+      /* cooked tracks eliminate all header/footer data */
+      track->stream_sector_size        = 2048;
+      track->stream_sector_header_size = 0;
+   }
+   else if ((size % 2336) == 0)
+   {
+      /* MODE 2 format without 16-byte sync data */
+      track->stream_sector_size        = 2336;
+      track->stream_sector_header_size = 8;
+   }
+}
+
+static void cdfs_seek_track_sector(cdfs_track_t* track, unsigned int sector)
+{
+   intfstream_seek(track->stream,
+           sector * track->stream_sector_size
+         + track->stream_sector_header_size
+         + track->first_sector_offset, SEEK_SET);
+}
+
+void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector)
+{
+   /* only allowed if open_file was called with a NULL path */
+   if (file->first_sector == 0)
+   {
+      if (file->current_sector != (int)sector)
+      {
+         file->current_sector      = (int)sector;
+         file->sector_buffer_valid = 0;
+      }
+
+      file->pos                    = sector * 2048;
+      file->current_sector_offset  = 0;
+   }
+}
+
+uint32_t cdfs_get_num_sectors(cdfs_file_t* file)
+{
+   uint32_t frame_size = intfstream_get_frame_size(file->track->stream);
+   if (frame_size == 0)
+   {
+      frame_size = file->track->stream_sector_size;
+      if (frame_size == 0)
+         frame_size = 1; /* prevent divide by 0 error if sector size is unknown */
+   }
+   return (uint32_t)(intfstream_get_size(file->track->stream) / frame_size);
+}
+
+uint32_t cdfs_get_first_sector(cdfs_file_t* file)
+{
+   return file->track->first_sector_index;
+}
+
+static int cdfs_find_file(cdfs_file_t* file, const char* path)
+{
+   size_t path_length;
+   int sector;
+   uint8_t buffer[2048], *tmp;
+   const char* slash = strrchr(path, '\\');
+
+   if (slash)
+   {
+      /* navigate the path to the directory record for the file */
+      const int dir_length = (int)(slash - path);
+      memcpy(buffer, path, dir_length);
+      buffer[dir_length] = '\0';
+
+      sector = cdfs_find_file(file, (const char*)buffer);
+      if (sector < 0)
+         return sector;
+
+      path += dir_length + 1;
+   }
+   else
+   {
+      int offset;
+
+      /* find the CD information (always 16 frames in) */
+      cdfs_seek_track_sector(file->track, 16);
+      intfstream_read(file->track->stream, buffer, sizeof(buffer));
+
+      /* the directory_record starts at 156 bytes into the sector.
+       * the sector containing the root directory contents is a 
+       * 3 byte value that is 2 bytes into the directory_record. */
+      offset = 156 + 2;
+      sector = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16);
+   }
+
+   /* process the contents of the directory */
+   cdfs_seek_track_sector(file->track, sector);
+   intfstream_read(file->track->stream, buffer, sizeof(buffer));
+
+   path_length = strlen(path);
+   tmp         = buffer;
+
+   while (tmp < buffer + sizeof(buffer))
+   {
+      /* The first byte of the record is the length of 
+       * the record - if 0, we reached the end of the data */
+      if (!*tmp)
+         break;
+
+      /* filename is 33 bytes into the record and 
+       * the format is "FILENAME;version" or "DIRECTORY" */
+      if (        (tmp[33 + path_length] == ';' 
+               || (tmp[33 + path_length] == '\0'))
+               &&  strncasecmp((const char*)(tmp + 33), path, path_length) == 0)
+      {
+         /* the file size is in bytes 10-13 of the record */
+         file->size = 
+              (tmp[10])
+            | (tmp[11] << 8) 
+            | (tmp[12] << 16) 
+            | (tmp[13] << 24);
+
+         /* the file contents are in the sector identified 
+          * in bytes 2-4 of the record */
+         sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);
+         return sector;
+      }
+
+      /* the first byte of the record is the length of the record */
+      tmp += tmp[0];
+   }
+
+   return -1;
+}
+
+int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* track, const char* path)
+{
+   if (!file || !track)
+      return 0;
+
+   memset(file, 0, sizeof(*file));
+
+   file->track          = track;
+   file->current_sector = -1;
+   file->first_sector   = -1;
+
+   if (path)
+      file->first_sector = cdfs_find_file(file, path);
+   else if (file->track->stream_sector_size)
+   {
+      file->first_sector = 0;
+      file->size         = (unsigned int)((intfstream_get_size(
+               file->track->stream) / file->track->stream_sector_size) 
+         * 2048);
+      return 1;
+   }
+
+   return (file->first_sector >= 0);
+}
+
+int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
+{
+   int bytes_read = 0;
+
+   if (!file || file->first_sector < 0 || !buffer)
+      return 0;
+
+   if (len > file->size - file->pos)
+      len = file->size - file->pos;
+
+   if (len == 0)
+      return 0;
+
+   if (file->sector_buffer_valid)
+   {
+      size_t remaining = 2048 - file->current_sector_offset;
+      if (remaining > 0)
+      {
+         if (remaining >= len)
+         {
+            memcpy(buffer,
+                  &file->sector_buffer[file->current_sector_offset],
+                  (size_t)len);
+            file->current_sector_offset += len;
+            return len;
+         }
+
+         memcpy(buffer,
+               &file->sector_buffer[file->current_sector_offset], remaining);
+         buffer      = (char*)buffer + remaining;
+         bytes_read += remaining;
+         len        -= remaining;
+
+         file->current_sector_offset += remaining;
+      }
+
+      ++file->current_sector;
+      file->current_sector_offset = 0;
+      file->sector_buffer_valid   = 0;
+   }
+   else if (file->current_sector < file->first_sector)
+   {
+      file->current_sector        = file->first_sector;
+      file->current_sector_offset = 0;
+   }
+
+   while (len >= 2048)
+   {
+      cdfs_seek_track_sector(file->track, file->current_sector);
+      intfstream_read(file->track->stream, buffer, 2048);
+
+      buffer      = (char*)buffer + 2048;
+      bytes_read += 2048;
+
+      ++file->current_sector;
+
+      len        -= 2048;
+   }
+
+   if (len > 0)
+   {
+      cdfs_seek_track_sector(file->track, file->current_sector);
+      intfstream_read(file->track->stream, file->sector_buffer, 2048);
+      memcpy(buffer, file->sector_buffer, (size_t)len);
+      file->current_sector_offset = (unsigned int)len;
+      file->sector_buffer_valid   = 1;
+
+      bytes_read += len;
+   }
+
+   file->pos += bytes_read;
+   return bytes_read;
+}
+
+void cdfs_close_file(cdfs_file_t* file)
+{
+   /* Not really anything to do here, just 
+    * clear out the first_sector so 
+    * read() won't do anything */
+   if (file)
+      file->first_sector = -1;
+}
+
+int64_t cdfs_get_size(cdfs_file_t* file)
+{
+   if (!file || file->first_sector < 0)
+      return 0;
+   return file->size;
+}
+
+int64_t cdfs_tell(cdfs_file_t* file)
+{
+   if (!file || file->first_sector < 0)
+      return -1;
+   return file->pos;
+}
+
+int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence)
+{
+   int64_t new_pos;
+   int new_sector;
+
+   if (!file || file->first_sector < 0)
+      return -1;
+
+   switch (whence)
+   {
+      case SEEK_SET:
+         new_pos = offset;
+         break;
+
+      case SEEK_CUR:
+         new_pos = file->pos + offset;
+         break;
+
+      case SEEK_END:
+         new_pos = file->size - offset;
+         break;
+
+      default:
+         return -1;
+   }
+
+   if (new_pos < 0)
+      return -1;
+   else if (new_pos > file->size)
+      return -1;
+
+   file->pos = (unsigned int)new_pos;
+   file->current_sector_offset = file->pos % 2048;
+
+   new_sector = file->pos / 2048;
+   if (new_sector != file->current_sector)
+   {
+      file->current_sector      = new_sector;
+      file->sector_buffer_valid = false;
+   }
+
+   return 0;
+}
+
+static void cdfs_skip_spaces(const char** ptr)
+{
+   while (**ptr && (**ptr == ' ' || **ptr == '\t'))
+      ++(*ptr);
+}
+
+static cdfs_track_t* cdfs_wrap_stream(
+      intfstream_t* stream,
+      unsigned first_sector_offset,
+      unsigned first_sector_index)
+{
+   cdfs_track_t* track = NULL;
+
+   if (!stream)
+      return NULL;
+
+   track                      = (cdfs_track_t*)
+      calloc(1, sizeof(*track));
+   track->stream              = stream;
+   track->first_sector_offset = first_sector_offset;
+   track->first_sector_index  = first_sector_index;
+
+   cdfs_determine_sector_size(track);
+
+   return track;
+}
+
+static cdfs_track_t* cdfs_open_cue_track(
+      const char* path, unsigned int track_index)
+{
+   char* cue                                = NULL;
+   const char* line                         = NULL;
+   int found_track                          = 0;
+   char current_track_path[PATH_MAX_LENGTH] = {0};
+   char track_path[PATH_MAX_LENGTH]         = {0};
+   unsigned int sector_size                 = 0;
+   unsigned int previous_sector_size        = 0;
+   unsigned int previous_index_sector_offset= 0;
+   unsigned int track_offset                = 0;
+   intfstream_t *cue_stream                 = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   int64_t stream_size                      = intfstream_get_size(cue_stream);
+   char *cue_contents                       = (char*)malloc((size_t)(stream_size + 1));
+   cdfs_track_t* track                      = NULL;
+
+   if (!cue_contents)
+   {
+      intfstream_close(cue_stream);
+      return NULL;
+   }
+
+   intfstream_read(cue_stream, cue_contents, stream_size);
+   intfstream_close(cue_stream);
+
+   cue_contents[stream_size] = '\0';
+
+   cue = cue_contents;
+   while (*cue)
+   {
+      cdfs_skip_spaces((const char**)&cue);
+      line = cue;
+
+      while (*cue && *cue != '\n')
+         ++cue;
+      if (*cue)
+         *cue++ = '\0';
+
+      if (!strncasecmp(line, "FILE", 4))
+      {
+         const char *file = line + 4;
+         cdfs_skip_spaces(&file);
+
+         if (file[0])
+         {
+            const char *file_end = cue - 1;
+            while (file_end > file && *file_end != ' ' && *file_end != '\t')
+               --file_end;
+
+            if (     file[0]      == '"' 
+                  && file_end[-1] == '"')
+            {
+               ++file;
+               --file_end;
+            }
+
+            memcpy(current_track_path, file, file_end - file);
+            current_track_path[file_end - file] = '\0';
+         }
+
+         previous_sector_size = 0;
+         previous_index_sector_offset = 0;
+         track_offset = 0;
+      }
+      else if (!strncasecmp(line, "TRACK", 5))
+      {
+         char *ptr             = NULL;
+         unsigned track_number = 0;
+         const char *track     = line + 5;
+         cdfs_skip_spaces(&track);
+
+         track_number = (unsigned)strtol(track, &ptr, 10);
+         while (*track && *track != ' ' && *track != '\n')
+            ++track;
+
+         previous_sector_size = sector_size;
+
+         cdfs_skip_spaces(&track);
+
+         if (!strncasecmp(track, "MODE", 4))
+         {
+            /* track_index = 0 means find the first data track */
+            if (!track_index || track_index == track_number)
+               found_track = track_number;
+
+            sector_size = atoi(track + 6);
+         }
+         else /* assume AUDIO */
+            sector_size = 2352;
+      }
+      else if (!strncasecmp(line, "INDEX", 5))
+      {
+         unsigned sector_offset;
+         unsigned min = 0, sec = 0, frame = 0;
+         unsigned index_number = 0;
+         const char *index     = line + 5;
+
+         cdfs_skip_spaces(&index);
+         sscanf(index, "%u", &index_number);
+         while (*index && *index != ' ' && *index != '\n')
+            ++index;
+         cdfs_skip_spaces(&index);
+
+         sscanf(index, "%u:%u:%u", &min, &sec, &frame);
+         sector_offset                 = ((min * 60) + sec) * 75 + frame;
+         sector_offset                -= previous_index_sector_offset;
+         track_offset                 += sector_offset * previous_sector_size;
+         previous_sector_size          = sector_size;
+         previous_index_sector_offset += sector_offset;
+
+         if (found_track && index_number == 1)
+         {
+            if (     strstr(current_track_path, "/")
+                  || strstr(current_track_path, "\\"))
+               strncpy(track_path, current_track_path, sizeof(track_path));
+            else
+            {
+               fill_pathname_basedir(track_path, path, sizeof(track_path));
+               strlcat(track_path, current_track_path, sizeof(track_path));
+            }
+
+            break;
+         }
+      }
+   }
+
+   free(cue_contents);
+
+   if (string_is_empty(track_path))
+      return NULL;
+
+   /* NOTE: previous_index_sector_offset will only be valid if all tracks are in the same BIN file.
+    * Otherwise, we need to determine how many tracks are in each previous BIN file, which is not
+    * stored in the CUE file. This will affect cdfs_get_first_sector, which luckily isn't used much. */
+   track = cdfs_wrap_stream(intfstream_open_file(
+            track_path, RETRO_VFS_FILE_ACCESS_READ,
+            RETRO_VFS_FILE_ACCESS_HINT_NONE), track_offset, previous_index_sector_offset);
+
+   if (track && track->stream_sector_size == 0)
+   {
+      track->stream_sector_size = sector_size;
+
+      if (sector_size == 2352)
+         track->stream_sector_header_size = 16;
+      else if (sector_size == 2336)
+         track->stream_sector_header_size = 8;
+   }
+
+   return track;
+}
+
+#ifdef HAVE_CHD
+static cdfs_track_t* cdfs_open_chd_track(const char* path, int32_t track_index)
+{
+   cdfs_track_t *track;
+   intfstream_t *intf_stream = intfstream_open_chd_track(path,
+         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE,
+         track_index);
+   if (!intf_stream)
+      return NULL;
+
+   track = cdfs_wrap_stream(intf_stream,
+         intfstream_get_offset_to_start(intf_stream),
+         intfstream_get_first_sector(intf_stream));
+
+   if (track && track->stream_sector_header_size == 0)
+   {
+      track->stream_sector_size = intfstream_get_frame_size(intf_stream);
+
+      if (track->stream_sector_size == 2352)
+         track->stream_sector_header_size = 16;
+      else if (track->stream_sector_size == 2336)
+         track->stream_sector_header_size = 8;
+   }
+
+   return track;
+}
+#endif
+
+struct cdfs_track_t* cdfs_open_track(const char* path,
+      unsigned int track_index)
+{
+   const char* ext = path_get_extension(path);
+
+   if (string_is_equal_noncase(ext, "cue"))
+      return cdfs_open_cue_track(path, track_index);
+
+#ifdef HAVE_CHD
+   if (string_is_equal_noncase(ext, "chd"))
+      return cdfs_open_chd_track(path, track_index);
+#endif
+
+   /* if opening track 1, try opening as a raw track */
+   if (track_index == 1)
+      return cdfs_open_raw_track(path);
+
+   /* unsupported file type */
+   return NULL;
+}
+
+struct cdfs_track_t* cdfs_open_data_track(const char* path)
+{
+   const char* ext = path_get_extension(path);
+
+   if (string_is_equal_noncase(ext, "cue"))
+      return cdfs_open_cue_track(path, 0);
+
+#ifdef HAVE_CHD
+   if (string_is_equal_noncase(ext, "chd"))
+      return cdfs_open_chd_track(path, CHDSTREAM_TRACK_PRIMARY);
+#endif
+
+   /* unsupported file type - try opening as a raw track */
+   return cdfs_open_raw_track(path);
+}
+
+cdfs_track_t* cdfs_open_raw_track(const char* path)
+{
+   const char *ext     = path_get_extension(path);
+   cdfs_track_t *track = NULL;
+
+   if (     string_is_equal_noncase(ext, "bin")
+         || string_is_equal_noncase(ext, "iso"))
+   {
+      intfstream_t* file = intfstream_open_file(path,
+         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+      track = cdfs_wrap_stream(file, 0, 0);
+      if (track && track->stream_sector_size == 0)
+      {
+         cdfs_determine_sector_size_from_file_size(track);
+         if (track->stream_sector_size == 0)
+         {
+            cdfs_close_track(track);
+            track = NULL;
+         }
+      }
+   }
+
+   return track;
+}
+
+void cdfs_close_track(cdfs_track_t* track)
+{
+   if (track)
+   {
+      if (track->stream)
+      {
+         intfstream_close(track->stream);
+         free(track->stream);
+      }
+
+      free(track);
+   }
+}
diff --git a/deps/libretro-common/formats/image_texture.c b/deps/libretro-common/formats/image_texture.c
new file mode 100644 (file)
index 0000000..bfd7e78
--- /dev/null
@@ -0,0 +1,333 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (image_texture.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#include <boolean.h>
+#include <formats/image.h>
+#include <file/nbio.h>
+#include <string/stdstring.h>
+
+enum image_type_enum image_texture_get_type(const char *path)
+{
+   /* We are comparing against a fixed list of file
+    * extensions, the longest (jpeg) being 4 characters
+    * in length. We therefore only need to extract the first
+    * 5 characters from the extension of the input path
+    * to correctly validate a match */
+   const char *ext = NULL;
+   char ext_lower[6];
+
+   ext_lower[0] = '\0';
+
+   if (string_is_empty(path))
+      return IMAGE_TYPE_NONE;
+
+   /* Get file extension */
+   ext = strrchr(path, '.');
+
+   if (!ext || (*(++ext) == '\0'))
+      return IMAGE_TYPE_NONE;
+
+   /* Copy and convert to lower case */
+   strlcpy(ext_lower, ext, sizeof(ext_lower));
+   string_to_lower(ext_lower);
+
+#ifdef HAVE_RPNG
+   if (string_is_equal(ext_lower, "png"))
+      return IMAGE_TYPE_PNG;
+#endif
+#ifdef HAVE_RJPEG
+   if (string_is_equal(ext_lower, "jpg") ||
+       string_is_equal(ext_lower, "jpeg"))
+      return IMAGE_TYPE_JPEG;
+#endif
+#ifdef HAVE_RBMP
+   if (string_is_equal(ext_lower, "bmp"))
+      return IMAGE_TYPE_BMP;
+#endif
+#ifdef HAVE_RTGA
+   if (string_is_equal(ext_lower, "tga"))
+      return IMAGE_TYPE_TGA;
+#endif
+
+   return IMAGE_TYPE_NONE;
+}
+
+bool image_texture_set_color_shifts(
+      unsigned *r_shift, unsigned *g_shift, unsigned *b_shift,
+      unsigned *a_shift,
+      struct texture_image *out_img
+      )
+{
+   *a_shift             = 24;
+   *r_shift             = 16;
+   *g_shift             = 8;
+   *b_shift             = 0;
+
+   if (out_img->supports_rgba)
+   {
+      *r_shift = 0;
+      *b_shift = 16;
+      return true;
+   }
+
+   return false;
+}
+
+bool image_texture_color_convert(unsigned r_shift,
+      unsigned g_shift, unsigned b_shift, unsigned a_shift,
+      struct texture_image *out_img)
+{
+   /* This is quite uncommon. */
+   if (a_shift != 24 || r_shift != 16 || g_shift != 8 || b_shift != 0)
+   {
+      uint32_t i;
+      uint32_t num_pixels = out_img->width * out_img->height;
+      uint32_t *pixels    = (uint32_t*)out_img->pixels;
+
+      for (i = 0; i < num_pixels; i++)
+      {
+         uint32_t col = pixels[i];
+         uint8_t a    = (uint8_t)(col >> 24);
+         uint8_t r    = (uint8_t)(col >> 16);
+         uint8_t g    = (uint8_t)(col >>  8);
+         uint8_t b    = (uint8_t)(col >>  0);
+         /* Explicitly cast these to uint32_t to prevent
+          * ASAN runtime error: left shift of 255 by 24 places
+          * cannot be represented in type 'int' */
+         pixels[i]    = ((uint32_t)a << a_shift) |
+                        ((uint32_t)r << r_shift) |
+                        ((uint32_t)g << g_shift) |
+                        ((uint32_t)b << b_shift);
+      }
+
+      return true;
+   }
+
+   return false;
+}
+
+#ifdef GEKKO
+
+#define GX_BLIT_LINE_32(off) \
+{ \
+   unsigned x; \
+   const uint16_t *tmp_src = src; \
+   uint16_t       *tmp_dst = dst; \
+   for (x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \
+   { \
+      tmp_dst[  0 + off] = tmp_src[0]; \
+      tmp_dst[ 16 + off] = tmp_src[1]; \
+      tmp_dst[  1 + off] = tmp_src[2]; \
+      tmp_dst[ 17 + off] = tmp_src[3]; \
+      tmp_dst[  2 + off] = tmp_src[4]; \
+      tmp_dst[ 18 + off] = tmp_src[5]; \
+      tmp_dst[  3 + off] = tmp_src[6]; \
+      tmp_dst[ 19 + off] = tmp_src[7]; \
+   } \
+   src += tmp_pitch; \
+}
+
+static bool image_texture_internal_gx_convert_texture32(
+      struct texture_image *image)
+{
+   unsigned tmp_pitch, width2, i;
+   const uint16_t *src = NULL;
+   uint16_t *dst       = NULL;
+   /* Memory allocation in libogc is extremely primitive so try
+    * to avoid gaps in memory when converting by copying over to
+    * a temporary buffer first, then converting over into
+    * main buffer again. */
+   void *tmp           = malloc(image->width
+         * image->height * sizeof(uint32_t));
+
+   if (!tmp)
+      return false;
+
+   memcpy(tmp, image->pixels, image->width
+         * image->height * sizeof(uint32_t));
+   tmp_pitch = (image->width * sizeof(uint32_t)) >> 1;
+
+   image->width       &= ~3;
+   image->height      &= ~3;
+   width2              = image->width << 1;
+   src                 = (uint16_t*)tmp;
+   dst                 = (uint16_t*)image->pixels;
+
+   for (i = 0; i < image->height; i += 4, dst += 4 * width2)
+   {
+      GX_BLIT_LINE_32(0)
+      GX_BLIT_LINE_32(4)
+      GX_BLIT_LINE_32(8)
+      GX_BLIT_LINE_32(12)
+   }
+
+   free(tmp);
+   return true;
+}
+#endif
+
+static bool image_texture_load_internal(
+      enum image_type_enum type,
+      void *ptr,
+      size_t len,
+      struct texture_image *out_img,
+      unsigned a_shift, unsigned r_shift,
+      unsigned g_shift, unsigned b_shift)
+{
+   int ret;
+   bool success = false;
+   void *img    = image_transfer_new(type);
+
+   if (!img)
+      goto end;
+
+   image_transfer_set_buffer_ptr(img, type, (uint8_t*)ptr, len);
+
+   if (!image_transfer_start(img, type))
+      goto end;
+
+   while (image_transfer_iterate(img, type));
+
+   if (!image_transfer_is_valid(img, type))
+      goto end;
+
+   do
+   {
+      ret = image_transfer_process(img, type,
+            (uint32_t**)&out_img->pixels, len, &out_img->width,
+            &out_img->height);
+   } while (ret == IMAGE_PROCESS_NEXT);
+
+   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
+      goto end;
+
+   image_texture_color_convert(r_shift, g_shift, b_shift,
+         a_shift, out_img);
+
+#ifdef GEKKO
+   if (!image_texture_internal_gx_convert_texture32(out_img))
+   {
+      image_texture_free(out_img);
+      goto end;
+   }
+#endif
+
+   success = true;
+
+end:
+   if (img)
+      image_transfer_free(img, type);
+
+   return success;
+}
+
+void image_texture_free(struct texture_image *img)
+{
+   if (!img)
+      return;
+
+   if (img->pixels)
+      free(img->pixels);
+   img->width  = 0;
+   img->height = 0;
+   img->pixels = NULL;
+}
+
+bool image_texture_load_buffer(struct texture_image *out_img,
+   enum image_type_enum type, void *buffer, size_t buffer_len)
+{
+   unsigned r_shift, g_shift, b_shift, a_shift;
+   image_texture_set_color_shifts(&r_shift, &g_shift, &b_shift,
+      &a_shift, out_img);
+
+   if (type != IMAGE_TYPE_NONE)
+   {
+      if (image_texture_load_internal(
+         type, buffer, buffer_len, out_img,
+         a_shift, r_shift, g_shift, b_shift))
+      {
+         return true;
+      }
+   }
+
+   out_img->supports_rgba = false;
+   out_img->pixels = NULL;
+   out_img->width = 0;
+   out_img->height = 0;
+
+   return false;
+}
+
+bool image_texture_load(struct texture_image *out_img,
+      const char *path)
+{
+   unsigned r_shift, g_shift, b_shift, a_shift;
+   size_t file_len             = 0;
+   struct nbio_t      *handle  = NULL;
+   void                   *ptr = NULL;
+   enum image_type_enum type  = image_texture_get_type(path);
+
+   image_texture_set_color_shifts(&r_shift, &g_shift, &b_shift,
+         &a_shift, out_img);
+
+   if (type != IMAGE_TYPE_NONE)
+   {
+      handle = (struct nbio_t*)nbio_open(path, NBIO_READ);
+      if (!handle)
+         goto error;
+      nbio_begin_read(handle);
+
+      while (!nbio_iterate(handle));
+
+      ptr = nbio_get_ptr(handle, &file_len);
+
+      if (!ptr)
+         goto error;
+
+      if (image_texture_load_internal(
+               type,
+               ptr, file_len, out_img,
+               a_shift, r_shift, g_shift, b_shift))
+         goto success;
+   }
+
+error:
+   out_img->supports_rgba = false;
+   out_img->pixels        = NULL;
+   out_img->width         = 0;
+   out_img->height        = 0;
+   if (handle)
+      nbio_free(handle);
+
+   return false;
+
+success:
+   if (handle)
+      nbio_free(handle);
+
+   return true;
+}
diff --git a/deps/libretro-common/formats/image_transfer.c b/deps/libretro-common/formats/image_transfer.c
new file mode 100644 (file)
index 0000000..76759ef
--- /dev/null
@@ -0,0 +1,285 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (image_transfer.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <string.h>
+
+#include <boolean.h>
+
+#ifdef HAVE_RPNG
+#include <formats/rpng.h>
+#endif
+#ifdef HAVE_RJPEG
+#include <formats/rjpeg.h>
+#endif
+#ifdef HAVE_RTGA
+#include <formats/rtga.h>
+#endif
+#ifdef HAVE_RBMP
+#include <formats/rbmp.h>
+#endif
+
+#include <formats/image.h>
+
+void image_transfer_free(void *data, enum image_type_enum type)
+{
+   switch (type)
+   {
+      case IMAGE_TYPE_TGA:
+#ifdef HAVE_RTGA
+         rtga_free((rtga_t*)data);
+#endif
+         break;
+      case IMAGE_TYPE_PNG:
+         {
+#ifdef HAVE_RPNG
+            rpng_t *rpng = (rpng_t*)data;
+            if (rpng)
+               rpng_free(rpng);
+#endif
+         }
+         break;
+      case IMAGE_TYPE_JPEG:
+#ifdef HAVE_RJPEG
+         rjpeg_free((rjpeg_t*)data);
+#endif
+         break;
+      case IMAGE_TYPE_BMP:
+#ifdef HAVE_RBMP
+         rbmp_free((rbmp_t*)data);
+#endif
+         break;
+      case IMAGE_TYPE_NONE:
+         break;
+   }
+}
+
+void *image_transfer_new(enum image_type_enum type)
+{
+   switch (type)
+   {
+      case IMAGE_TYPE_PNG:
+#ifdef HAVE_RPNG
+         return rpng_alloc();
+#else
+         break;
+#endif
+      case IMAGE_TYPE_JPEG:
+#ifdef HAVE_RJPEG
+         return rjpeg_alloc();
+#else
+         break;
+#endif
+      case IMAGE_TYPE_TGA:
+#ifdef HAVE_RTGA
+         return rtga_alloc();
+#else
+         break;
+#endif
+      case IMAGE_TYPE_BMP:
+#ifdef HAVE_RBMP
+         return rbmp_alloc();
+#else
+         break;
+#endif
+      default:
+         break;
+   }
+
+   return NULL;
+}
+
+bool image_transfer_start(void *data, enum image_type_enum type)
+{
+
+   switch (type)
+   {
+      case IMAGE_TYPE_PNG:
+#ifdef HAVE_RPNG
+         if (!rpng_start((rpng_t*)data))
+            break;
+         return true;
+#else
+         break;
+#endif
+      case IMAGE_TYPE_JPEG:
+#ifdef HAVE_RJPEG
+         return true;
+#else
+         break;
+#endif
+      case IMAGE_TYPE_TGA:
+#ifdef HAVE_RTGA
+         return true;
+#else
+         break;
+#endif
+      case IMAGE_TYPE_BMP:
+         return true;
+      case IMAGE_TYPE_NONE:
+         break;
+   }
+
+   return false;
+}
+
+bool image_transfer_is_valid(
+      void *data,
+      enum image_type_enum type)
+{
+   switch (type)
+   {
+      case IMAGE_TYPE_PNG:
+#ifdef HAVE_RPNG
+         return rpng_is_valid((rpng_t*)data);
+#else
+         break;
+#endif
+      case IMAGE_TYPE_JPEG:
+#ifdef HAVE_RJPEG
+         return true;
+#else
+         break;
+#endif
+      case IMAGE_TYPE_TGA:
+#ifdef HAVE_RTGA
+         return true;
+#else
+         break;
+#endif
+      case IMAGE_TYPE_BMP:
+         return true;
+      case IMAGE_TYPE_NONE:
+         break;
+   }
+
+   return false;
+}
+
+void image_transfer_set_buffer_ptr(
+      void *data,
+      enum image_type_enum type,
+      void *ptr,
+      size_t len)
+{
+   switch (type)
+   {
+      case IMAGE_TYPE_PNG:
+#ifdef HAVE_RPNG
+         rpng_set_buf_ptr((rpng_t*)data, (uint8_t*)ptr, len);
+#endif
+         break;
+      case IMAGE_TYPE_JPEG:
+#ifdef HAVE_RJPEG
+         rjpeg_set_buf_ptr((rjpeg_t*)data, (uint8_t*)ptr);
+#endif
+         break;
+      case IMAGE_TYPE_TGA:
+#ifdef HAVE_RTGA
+         rtga_set_buf_ptr((rtga_t*)data, (uint8_t*)ptr);
+#endif
+         break;
+      case IMAGE_TYPE_BMP:
+#ifdef HAVE_RBMP
+         rbmp_set_buf_ptr((rbmp_t*)data, (uint8_t*)ptr);
+#endif
+         break;
+      case IMAGE_TYPE_NONE:
+         break;
+   }
+}
+
+int image_transfer_process(
+      void *data,
+      enum image_type_enum type,
+      uint32_t **buf, size_t len,
+      unsigned *width, unsigned *height)
+{
+   switch (type)
+   {
+      case IMAGE_TYPE_PNG:
+#ifdef HAVE_RPNG
+         return rpng_process_image(
+               (rpng_t*)data,
+               (void**)buf, len, width, height);
+#else
+         break;
+#endif
+      case IMAGE_TYPE_JPEG:
+#ifdef HAVE_RJPEG
+         return rjpeg_process_image((rjpeg_t*)data,
+               (void**)buf, len, width, height);
+#else
+         break;
+#endif
+      case IMAGE_TYPE_TGA:
+#ifdef HAVE_RTGA
+         return rtga_process_image((rtga_t*)data,
+               (void**)buf, len, width, height);
+#else
+         break;
+#endif
+      case IMAGE_TYPE_BMP:
+#ifdef HAVE_RBMP
+         return rbmp_process_image((rbmp_t*)data,
+               (void**)buf, len, width, height);
+#else
+         break;
+#endif
+      case IMAGE_TYPE_NONE:
+         break;
+   }
+
+   return 0;
+}
+
+bool image_transfer_iterate(void *data, enum image_type_enum type)
+{
+
+   switch (type)
+   {
+      case IMAGE_TYPE_PNG:
+#ifdef HAVE_RPNG
+         if (!rpng_iterate_image((rpng_t*)data))
+            return false;
+#endif
+         break;
+      case IMAGE_TYPE_JPEG:
+#ifdef HAVE_RJPEG
+         return false;
+#else
+         break;
+#endif
+      case IMAGE_TYPE_TGA:
+#ifdef HAVE_RTGA
+         return false;
+#else
+         break;
+#endif
+      case IMAGE_TYPE_BMP:
+         return false;
+      case IMAGE_TYPE_NONE:
+         return false;
+   }
+
+   return true;
+}
diff --git a/deps/libretro-common/formats/jpeg/rjpeg.c b/deps/libretro-common/formats/jpeg/rjpeg.c
new file mode 100644 (file)
index 0000000..166731c
--- /dev/null
@@ -0,0 +1,2632 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rjpeg.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* Modified version of stb_image's JPEG sources. */
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <stddef.h> /* ptrdiff_t on osx */
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_inline.h>
+#include <boolean.h>
+#include <formats/image.h>
+#include <formats/rjpeg.h>
+#include <features/features_cpu.h>
+
+enum
+{
+   RJPEG_DEFAULT = 0, /* only used for req_comp */
+   RJPEG_GREY,
+   RJPEG_GREY_ALPHA,
+   RJPEG_RGB,
+   RJPEG_RGB_ALPHA
+};
+
+enum
+{
+   RJPEG_SCAN_LOAD = 0,
+   RJPEG_SCAN_TYPE,
+   RJPEG_SCAN_HEADER
+};
+
+typedef uint8_t *(*rjpeg_resample_row_func)(uint8_t *out, uint8_t *in0, uint8_t *in1,
+                                    int w, int hs);
+
+typedef struct
+{
+   rjpeg_resample_row_func resample;
+   uint8_t *line0;
+   uint8_t *line1;
+   int hs,vs;   /* expansion factor in each axis */
+   int w_lores; /* horizontal pixels pre-expansion */
+   int ystep;   /* how far through vertical expansion we are */
+   int ypos;    /* which pre-expansion row we're on */
+} rjpeg_resample;
+
+struct rjpeg
+{
+   uint8_t *buff_data;
+};
+
+#ifdef _MSC_VER
+#define RJPEG_HAS_LROTL
+#endif
+
+#ifdef RJPEG_HAS_LROTL
+   #define RJPEG_LROT(x,y)  _lrotl(x,y)
+#else
+   #define RJPEG_LROT(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+/* x86/x64 detection */
+#if defined(__x86_64__) || defined(_M_X64)
+#define RJPEG_X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define RJPEG_X86_TARGET
+#endif
+
+#if defined(__GNUC__) && (defined(RJPEG_X86_TARGET) || defined(RJPEG_X64_TARGET)) && !defined(__SSE2__) && !defined(RJPEG_NO_SIMD)
+/* NOTE: not clear do we actually need this for the 64-bit path?
+ * gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+ * (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
+ * this is just broken and gcc are jerks for not fixing it properly
+ * http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
+ */
+#define RJPEG_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(RJPEG_X86_TARGET) && !defined(RJPEG_MINGW_ENABLE_SSE2) && !defined(RJPEG_NO_SIMD)
+/* Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid RJPEG_X64_TARGET
+ *
+ * 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+ * Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+ * As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+ * simultaneously enabling "-mstackrealign".
+ *
+ * See https://github.com/nothings/stb/issues/81 for more information.
+ *
+ * So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+ * -mstackrealign to your build settings, feel free to #define RJPEG_MINGW_ENABLE_SSE2.
+ */
+#define RJPEG_NO_SIMD
+#endif
+
+#if defined(__SSE2__)
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+#define RJPEG_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+#else
+#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#endif
+
+/* ARM NEON */
+#if defined(RJPEG_NO_SIMD) && defined(RJPEG_NEON)
+#undef RJPEG_NEON
+#endif
+
+#ifdef RJPEG_NEON
+#include <arm_neon.h>
+/* assume GCC or Clang on ARM targets */
+#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef RJPEG_SIMD_ALIGN
+#define RJPEG_SIMD_ALIGN(type, name) type name
+#endif
+
+typedef struct
+{
+   uint8_t *img_buffer;
+   uint8_t *img_buffer_end;
+   uint8_t *img_buffer_original;
+   int      img_n;
+   int      img_out_n;
+   int      buflen;
+   uint32_t img_x;
+   uint32_t img_y;
+   uint8_t  buffer_start[128];
+} rjpeg_context;
+
+static INLINE uint8_t rjpeg_get8(rjpeg_context *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+
+   return 0;
+}
+
+#define RJPEG_AT_EOF(s)     ((s)->img_buffer >= (s)->img_buffer_end)
+
+#define RJPEG_GET16BE(s)    ((rjpeg_get8((s)) << 8) + rjpeg_get8((s)))
+
+/* huffman decoding acceleration */
+#define FAST_BITS   9  /* larger handles more cases; smaller stomps less cache */
+
+typedef struct
+{
+   unsigned int maxcode[18];
+   int    delta[17];   /* old 'firstsymbol' - old 'firstcode' */
+   /* weirdly, repacking this into AoS is a 10% speed loss, instead of a win */
+   uint16_t code[256];
+   uint8_t  fast[1 << FAST_BITS];
+   uint8_t  values[256];
+   uint8_t  size[257];
+} rjpeg_huffman;
+
+typedef struct
+{
+   rjpeg_context *s;
+   /* kernels */
+   void (*idct_block_kernel)(uint8_t *out, int out_stride, short data[64]);
+   void (*YCbCr_to_RGB_kernel)(uint8_t *out, const uint8_t *y, const uint8_t *pcb,
+         const uint8_t *pcr, int count, int step);
+   uint8_t *(*resample_row_hv_2_kernel)(uint8_t *out, uint8_t *in_near,
+         uint8_t *in_far, int w, int hs);
+
+   /* definition of jpeg image component */
+   struct
+   {
+      uint8_t *data;
+      void *raw_data, *raw_coeff;
+      uint8_t *linebuf;
+      short   *coeff;            /* progressive only */
+      int id;
+      int h,v;
+      int tq;
+      int hd,ha;
+      int dc_pred;
+
+      int x,y,w2,h2;
+      int      coeff_w;          /* number of 8x8 coefficient blocks */
+      int      coeff_h;          /* number of 8x8 coefficient blocks */
+   } img_comp[4];
+
+   /* sizes for components, interleaved MCUs */
+   int img_h_max, img_v_max;
+   int img_mcu_x, img_mcu_y;
+   int img_mcu_w, img_mcu_h;
+
+   int            code_bits;     /* number of valid bits */
+   int            nomore;        /* flag if we saw a marker so must stop */
+   int            progressive;
+   int            spec_start;
+   int            spec_end;
+   int            succ_high;
+   int            succ_low;
+   int            eob_run;
+   int scan_n, order[4];
+   int restart_interval, todo;
+   uint32_t       code_buffer;   /* jpeg entropy-coded buffer */
+   rjpeg_huffman huff_dc[4];     /* unsigned int alignment */
+   rjpeg_huffman huff_ac[4];     /* unsigned int alignment */
+   int16_t fast_ac[4][1 << FAST_BITS];
+   unsigned char  marker;        /* marker seen while filling entropy buffer */
+   uint8_t dequant[4][64];
+} rjpeg_jpeg;
+
+#define RJPEG_F2F(x)  ((int) (((x) * 4096 + 0.5)))
+#define RJPEG_FSH(x)  ((x) << 12)
+
+#define RJPEG_MARKER_NONE  0xff
+/* if there's a pending marker from the entropy stream, return that
+ * otherwise, fetch from the stream and get a marker. if there's no
+ * marker, return 0xff, which is never a valid marker value
+ */
+
+/* in each scan, we'll have scan_n components, and the order
+ * of the components is specified by order[]
+ */
+#define RJPEG_RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
+
+#define JPEG_MARKER           0xFF
+#define JPEG_MARKER_SOI       0xD8
+#define JPEG_MARKER_SOS       0xDA
+#define JPEG_MARKER_EOI       0xD9
+#define JPEG_MARKER_APP1      0xE1
+#define JPEG_MARKER_APP2      0xE2
+
+/* use comparisons since in some cases we handle more than one case (e.g. SOF) */
+#define RJPEG_SOF(x)               ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+
+#define RJPEG_SOF_PROGRESSIVE(x)   ((x) == 0xc2)
+#define RJPEG_DIV4(x)              ((uint8_t) ((x) >> 2))
+#define RJPEG_DIV16(x)             ((uint8_t) ((x) >> 4))
+
+static int rjpeg_build_huffman(rjpeg_huffman *h, int *count)
+{
+   int i,j,k = 0,code;
+
+   /* build size list for each symbol (from JPEG spec) */
+   for (i = 0; i < 16; ++i)
+      for (j = 0; j < count[i]; ++j)
+         h->size[k++] = (uint8_t) (i+1);
+
+   h->size[k] = 0;
+   /* compute actual symbols (from jpeg spec) */
+   code       = 0;
+   k          = 0;
+
+   for (j = 1; j <= 16; ++j)
+   {
+      /* compute delta to add to code to compute symbol id */
+      h->delta[j] = k - code;
+      if (h->size[k] == j)
+      {
+         while (h->size[k] == j)
+            h->code[k++] = (uint16_t) (code++);
+
+         /* Bad code lengths, corrupt JPEG? */
+         if (code-1 >= (1 << j))
+            return 0;
+      }
+      /* compute largest code + 1 for this size, preshifted as needed later */
+      h->maxcode[j] = code << (16-j);
+      code <<= 1;
+   }
+   h->maxcode[j] = 0xffffffff;
+
+   /* build non-spec acceleration table; 255 is flag for not-accelerated */
+   memset(h->fast, 255, 1 << FAST_BITS);
+   for (i = 0; i < k; ++i)
+   {
+      int s = h->size[i];
+      if (s <= FAST_BITS)
+      {
+         int c = h->code[i] << (FAST_BITS-s);
+         int m = 1 << (FAST_BITS-s);
+         for (j = 0; j < m; ++j)
+            h->fast[c+j] = (uint8_t) i;
+      }
+   }
+   return 1;
+}
+
+/* build a table that decodes both magnitude and value of small ACs in
+ * one go. */
+static void rjpeg_build_fast_ac(int16_t *fast_ac, rjpeg_huffman *h)
+{
+   int i;
+
+   for (i = 0; i < (1 << FAST_BITS); ++i)
+   {
+      uint8_t fast = h->fast[i];
+
+      fast_ac[i] = 0;
+
+      if (fast < 255)
+      {
+         int rs      = h->values[fast];
+         int run     = (rs >> 4) & 15;
+         int magbits = rs & 15;
+         int len     = h->size[fast];
+
+         if (magbits && len + magbits <= FAST_BITS)
+         {
+            /* magnitude code followed by receive_extend code */
+            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+            int m = 1 << (magbits - 1);
+            if (k < m)
+               k += (-1 << magbits) + 1;
+
+            /* if the result is small enough, we can fit it in fast_ac table */
+            if (k >= -128 && k <= 127)
+               fast_ac[i] = (int16_t) ((k << 8) + (run << 4) + (len + magbits));
+         }
+      }
+   }
+}
+
+static void rjpeg_grow_buffer_unsafe(rjpeg_jpeg *j)
+{
+   do
+   {
+      int b = j->nomore ? 0 : rjpeg_get8(j->s);
+      if (b == 0xff)
+      {
+         int c = rjpeg_get8(j->s);
+
+         if (c != 0)
+         {
+            j->marker = (unsigned char) c;
+            j->nomore = 1;
+            return;
+         }
+      }
+      j->code_buffer |= b << (24 - j->code_bits);
+      j->code_bits   += 8;
+   } while (j->code_bits <= 24);
+}
+
+/* (1 << n) - 1 */
+static uint32_t rjpeg_bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+/* decode a JPEG huffman value from the bitstream */
+static INLINE int rjpeg_jpeg_huff_decode(rjpeg_jpeg *j, rjpeg_huffman *h)
+{
+   unsigned int temp;
+   int c,k;
+
+   if (j->code_bits < 16)
+      rjpeg_grow_buffer_unsafe(j);
+
+   /* look at the top FAST_BITS and determine what symbol ID it is,
+    * if the code is <= FAST_BITS */
+   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+   k = h->fast[c];
+
+   if (k < 255)
+   {
+      int s = h->size[k];
+      if (s > j->code_bits)
+         return -1;
+      j->code_buffer <<= s;
+      j->code_bits -= s;
+      return h->values[k];
+   }
+
+   /* naive test is to shift the code_buffer down so k bits are
+    * valid, then test against maxcode. To speed this up, we've
+    * preshifted maxcode left so that it has (16-k) 0s at the
+    * end; in other words, regardless of the number of bits, it
+    * wants to be compared against something shifted to have 16;
+    * that way we don't need to shift inside the loop. */
+   temp = j->code_buffer >> 16;
+   for (k=FAST_BITS+1 ; ; ++k)
+      if (temp < h->maxcode[k])
+         break;
+
+   if (k == 17)
+   {
+      /* error! code not found */
+      j->code_bits -= 16;
+      return -1;
+   }
+
+   if (k > j->code_bits)
+      return -1;
+
+   /* convert the huffman code to the symbol id */
+   c = ((j->code_buffer >> (32 - k)) & rjpeg_bmask[k]) + h->delta[k];
+
+   /* convert the id to a symbol */
+   j->code_bits -= k;
+   j->code_buffer <<= k;
+   return h->values[c];
+}
+
+/* bias[n] = (-1<<n) + 1 */
+static int const rjpeg_jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+/* combined JPEG 'receive' and JPEG 'extend', since baseline
+ * always extends everything it receives. */
+static INLINE int rjpeg_extend_receive(rjpeg_jpeg *j, int n)
+{
+   unsigned int k;
+   int sgn;
+   if (j->code_bits < n)
+      rjpeg_grow_buffer_unsafe(j);
+
+   sgn             = (int32_t)j->code_buffer >> 31; /* sign bit is always in MSB */
+   k               = RJPEG_LROT(j->code_buffer, n);
+   j->code_buffer  = k & ~rjpeg_bmask[n];
+   k              &= rjpeg_bmask[n];
+   j->code_bits   -= n;
+   return k + (rjpeg_jbias[n] & ~sgn);
+}
+
+/* get some unsigned bits */
+static INLINE int rjpeg_jpeg_get_bits(rjpeg_jpeg *j, int n)
+{
+   unsigned int k;
+   if (j->code_bits < n)
+      rjpeg_grow_buffer_unsafe(j);
+   k              = RJPEG_LROT(j->code_buffer, n);
+   j->code_buffer = k & ~rjpeg_bmask[n];
+   k             &= rjpeg_bmask[n];
+   j->code_bits  -= n;
+   return k;
+}
+
+static INLINE int rjpeg_jpeg_get_bit(rjpeg_jpeg *j)
+{
+   unsigned int k;
+   if (j->code_bits < 1)
+      rjpeg_grow_buffer_unsafe(j);
+
+   k                = j->code_buffer;
+   j->code_buffer <<= 1;
+   --j->code_bits;
+   return k & 0x80000000;
+}
+
+/* given a value that's at position X in the zigzag stream,
+ * where does it appear in the 8x8 matrix coded as row-major? */
+static uint8_t rjpeg_jpeg_dezigzag[64+15] =
+{
+    0,  1,  8, 16,  9,  2,  3, 10,
+   17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34,
+   27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36,
+   29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46,
+   53, 60, 61, 54, 47, 55, 62, 63,
+   /* let corrupt input sample past end */
+   63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63
+};
+
+/* decode one 64-entry block-- */
+static int rjpeg_jpeg_decode_block(
+      rjpeg_jpeg *j, short data[64],
+      rjpeg_huffman *hdc,
+      rjpeg_huffman *hac,
+      int16_t *fac,
+      int b,
+      uint8_t *dequant)
+{
+   int dc,k;
+   int t;
+   int diff      = 0;
+
+   if (j->code_bits < 16)
+      rjpeg_grow_buffer_unsafe(j);
+   t = rjpeg_jpeg_huff_decode(j, hdc);
+
+   /* Bad huffman code. Corrupt JPEG? */
+   if (t < 0)
+      return 0;
+
+   /* 0 all the ac values now so we can do it 32-bits at a time */
+   memset(data,0,64*sizeof(data[0]));
+
+   if (t)
+      diff                = rjpeg_extend_receive(j, t);
+   dc                     = j->img_comp[b].dc_pred + diff;
+   j->img_comp[b].dc_pred = dc;
+   data[0]                = (short) (dc * dequant[0]);
+
+   /* decode AC components, see JPEG spec */
+   k                      = 1;
+   do
+   {
+      unsigned int zig;
+      int c,r,s;
+      if (j->code_bits < 16)
+         rjpeg_grow_buffer_unsafe(j);
+      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+      r = fac[c];
+      if (r)
+      {
+         /* fast-AC path */
+         k               += (r >> 4) & 15; /* run */
+         s                = r & 15; /* combined length */
+         j->code_buffer <<= s;
+         j->code_bits    -= s;
+         /* decode into unzigzag'd location */
+         zig              = rjpeg_jpeg_dezigzag[k++];
+         data[zig]        = (short) ((r >> 8) * dequant[zig]);
+      }
+      else
+      {
+         int rs = rjpeg_jpeg_huff_decode(j, hac);
+
+         /* Bad huffman code. Corrupt JPEG? */
+         if (rs < 0)
+            return 0;
+
+         s = rs & 15;
+         r = rs >> 4;
+         if (s == 0)
+         {
+            if (rs != 0xf0)
+               break; /* end block */
+            k += 16;
+         }
+         else
+         {
+            k += r;
+            /* decode into unzigzag'd location */
+            zig = rjpeg_jpeg_dezigzag[k++];
+            data[zig] = (short) (rjpeg_extend_receive(j,s) * dequant[zig]);
+         }
+      }
+   } while (k < 64);
+   return 1;
+}
+
+static int rjpeg_jpeg_decode_block_prog_dc(
+      rjpeg_jpeg *j,
+      short data[64],
+      rjpeg_huffman *hdc,
+      int b)
+{
+   /* Can't merge DC and AC. Corrupt JPEG? */
+   if (j->spec_end != 0)
+      return 0;
+
+   if (j->code_bits < 16)
+      rjpeg_grow_buffer_unsafe(j);
+
+   if (j->succ_high == 0)
+   {
+      int t;
+      int dc;
+      int diff = 0;
+
+      /* first scan for DC coefficient, must be first */
+      memset(data,0,64*sizeof(data[0])); /* 0 all the ac values now */
+      t       = rjpeg_jpeg_huff_decode(j, hdc);
+      if (t)
+         diff = rjpeg_extend_receive(j, t);
+
+      dc      = j->img_comp[b].dc_pred + diff;
+      j->img_comp[b].dc_pred = dc;
+      data[0] = (short) (dc << j->succ_low);
+   }
+   else
+   {
+      /* refinement scan for DC coefficient */
+      if (rjpeg_jpeg_get_bit(j))
+         data[0] += (short) (1 << j->succ_low);
+   }
+   return 1;
+}
+
+static int rjpeg_jpeg_decode_block_prog_ac(
+      rjpeg_jpeg *j,
+      short data[64],
+      rjpeg_huffman *hac,
+      int16_t *fac)
+{
+   int k;
+
+   /* Can't merge DC and AC. Corrupt JPEG? */
+   if (j->spec_start == 0)
+      return 0;
+
+   if (j->succ_high == 0)
+   {
+      int shift = j->succ_low;
+
+      if (j->eob_run)
+      {
+         --j->eob_run;
+         return 1;
+      }
+
+      k = j->spec_start;
+      do
+      {
+         unsigned int zig;
+         int c,r,s;
+         if (j->code_bits < 16)
+            rjpeg_grow_buffer_unsafe(j);
+         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+         r = fac[c];
+         if (r)
+         {
+            /* fast-AC path */
+            k               += (r >> 4) & 15; /* run */
+            s                = r & 15; /* combined length */
+            j->code_buffer <<= s;
+            j->code_bits    -= s;
+            zig              = rjpeg_jpeg_dezigzag[k++];
+            data[zig]        = (short) ((r >> 8) << shift);
+         }
+         else
+         {
+            int rs = rjpeg_jpeg_huff_decode(j, hac);
+
+            /* Bad huffman code. Corrupt JPEG? */
+            if (rs < 0)
+               return 0;
+
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0)
+            {
+               if (r < 15)
+               {
+                  j->eob_run = (1 << r);
+                  if (r)
+                     j->eob_run += rjpeg_jpeg_get_bits(j, r);
+                  --j->eob_run;
+                  break;
+               }
+               k += 16;
+            }
+            else
+            {
+               k         += r;
+               zig        = rjpeg_jpeg_dezigzag[k++];
+               data[zig]  = (short) (rjpeg_extend_receive(j,s) << shift);
+            }
+         }
+      } while (k <= j->spec_end);
+   }
+   else
+   {
+      /* refinement scan for these AC coefficients */
+
+      short bit = (short) (1 << j->succ_low);
+
+      if (j->eob_run)
+      {
+         --j->eob_run;
+         for (k = j->spec_start; k <= j->spec_end; ++k)
+         {
+            short *p = &data[rjpeg_jpeg_dezigzag[k]];
+            if (*p != 0)
+               if (rjpeg_jpeg_get_bit(j))
+                  if ((*p & bit) == 0)
+                  {
+                     if (*p > 0)
+                        *p += bit;
+                     else
+                        *p -= bit;
+                  }
+         }
+      }
+      else
+      {
+         k = j->spec_start;
+         do
+         {
+            int r,s;
+            int rs = rjpeg_jpeg_huff_decode(j, hac);
+
+            /* Bad huffman code. Corrupt JPEG? */
+            if (rs < 0)
+               return 0;
+
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0)
+            {
+               if (r < 15)
+               {
+                  j->eob_run = (1 << r) - 1;
+                  if (r)
+                     j->eob_run += rjpeg_jpeg_get_bits(j, r);
+                  r = 64; /* force end of block */
+               }
+               else
+               {
+                  /* r=15 s=0 should write 16 0s, so we just do
+                   * a run of 15 0s and then write s (which is 0),
+                   * so we don't have to do anything special here */
+               }
+            }
+            else
+            {
+               /* Bad huffman code. Corrupt JPEG? */
+               if (s != 1)
+                  return 0;
+
+               /* sign bit */
+               if (rjpeg_jpeg_get_bit(j))
+                  s = bit;
+               else
+                  s = -bit;
+            }
+
+            /* advance by r */
+            while (k <= j->spec_end)
+            {
+               short *p = &data[rjpeg_jpeg_dezigzag[k++]];
+               if (*p != 0)
+               {
+                  if (rjpeg_jpeg_get_bit(j))
+                     if ((*p & bit) == 0)
+                     {
+                        if (*p > 0)
+                           *p += bit;
+                        else
+                           *p -= bit;
+                     }
+               }
+               else
+               {
+                  if (r == 0)
+                  {
+                     *p = (short) s;
+                     break;
+                  }
+                  --r;
+               }
+            }
+         } while (k <= j->spec_end);
+      }
+   }
+   return 1;
+}
+
+/* take a -128..127 value and rjpeg_clamp it and convert to 0..255 */
+static INLINE uint8_t rjpeg_clamp(int x)
+{
+   /* trick to use a single test to catch both cases */
+   if ((unsigned int) x > 255)
+      return 255;
+   return (uint8_t) x;
+}
+
+/* derived from jidctint -- DCT_ISLOW */
+#define RJPEG_IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+   int t0,t1,p4,p5,x0,x1,x2,x3; \
+   int p2 = s2;                                \
+   int p3 = s6;                                \
+   int p1 = (p2+p3) * RJPEG_F2F(0.5411961f);   \
+   int t2 = p1 + p3 * RJPEG_F2F(-1.847759065f);\
+   int t3 = p1 + p2 * RJPEG_F2F( 0.765366865f);\
+   p2 = s0;                                    \
+   p3 = s4;                                    \
+   t0 = RJPEG_FSH(p2+p3);                      \
+   t1 = RJPEG_FSH(p2-p3);                      \
+   x0 = t0+t3;                                 \
+   x3 = t0-t3;                                 \
+   x1 = t1+t2;                                 \
+   x2 = t1-t2;                                 \
+   t0 = s7;                                    \
+   t1 = s5;                                    \
+   t2 = s3;                                    \
+   t3 = s1;                                    \
+   p3 = t0+t2;                                 \
+   p4 = t1+t3;                                 \
+   p1 = t0+t3;                                 \
+   p2 = t1+t2;                                 \
+   p5 = (p3+p4) * RJPEG_F2F( 1.175875602f);    \
+   t0 = t0      * RJPEG_F2F( 0.298631336f);    \
+   t1 = t1      * RJPEG_F2F( 2.053119869f);    \
+   t2 = t2      * RJPEG_F2F( 3.072711026f);    \
+   t3 = t3      * RJPEG_F2F( 1.501321110f);    \
+   p1 = p5 + p1 * RJPEG_F2F(-0.899976223f);    \
+   p2 = p5 + p2 * RJPEG_F2F(-2.562915447f);    \
+   p3 = p3      * RJPEG_F2F(-1.961570560f);    \
+   p4 = p4      * RJPEG_F2F(-0.390180644f);    \
+   t3 += p1+p4;                                \
+   t2 += p2+p3;                                \
+   t1 += p2+p4;                                \
+   t0 += p1+p3
+
+static void rjpeg_idct_block(uint8_t *out, int out_stride, short data[64])
+{
+   int i,val[64],*v=val;
+   uint8_t   *o = NULL;
+   int16_t   *d = data;
+
+   /* columns */
+   for (i = 0; i < 8; ++i,++d, ++v)
+   {
+      /* if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing */
+      if (     d[ 8] == 0 
+            && d[16] == 0 
+            && d[24] == 0 
+            && d[32] == 0
+            && d[40] == 0
+            && d[48] == 0
+            && d[56] == 0)
+      {
+         /*    no shortcut                 0     seconds
+          *    (1|2|3|4|5|6|7)==0          0     seconds
+          *    all separate               -0.047 seconds
+          *    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds */
+         int dcterm = d[0] << 2;
+         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+      }
+      else
+      {
+         RJPEG_IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]);
+
+         /* constants scaled things up by 1<<12; let's bring them back
+          * down, but keep 2 extra bits of precision */
+         x0 += 512;
+         x1 += 512;
+         x2 += 512;
+         x3 += 512;
+
+         v[ 0] = (x0+t3) >> 10;
+         v[56] = (x0-t3) >> 10;
+         v[ 8] = (x1+t2) >> 10;
+         v[48] = (x1-t2) >> 10;
+         v[16] = (x2+t1) >> 10;
+         v[40] = (x2-t1) >> 10;
+         v[24] = (x3+t0) >> 10;
+         v[32] = (x3-t0) >> 10;
+      }
+   }
+
+   for (i = 0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride)
+   {
+      /* no fast case since the first 1D IDCT spread components out */
+      RJPEG_IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]);
+
+      /* constants scaled things up by 1<<12, plus we had 1<<2 from first
+       * loop, plus horizontal and vertical each scale by sqrt(8) so together
+       * we've got an extra 1<<3, so 1<<17 total we need to remove.
+       * so we want to round that, which means adding 0.5 * 1<<17,
+       * aka 65536. Also, we'll end up with -128 to 127 that we want
+       * to encode as 0..255 by adding 128, so we'll add that before the shift 
+       */
+      x0 += 65536 + (128<<17);
+      x1 += 65536 + (128<<17);
+      x2 += 65536 + (128<<17);
+      x3 += 65536 + (128<<17);
+
+      /* Tried computing the shifts into temps, or'ing the temps to see
+       * if any were out of range, but that was slower */
+      o[0] = rjpeg_clamp((x0+t3) >> 17);
+      o[7] = rjpeg_clamp((x0-t3) >> 17);
+      o[1] = rjpeg_clamp((x1+t2) >> 17);
+      o[6] = rjpeg_clamp((x1-t2) >> 17);
+      o[2] = rjpeg_clamp((x2+t1) >> 17);
+      o[5] = rjpeg_clamp((x2-t1) >> 17);
+      o[3] = rjpeg_clamp((x3+t0) >> 17);
+      o[4] = rjpeg_clamp((x3-t0) >> 17);
+   }
+}
+
+#if defined(__SSE2__)
+/* sse2 integer IDCT. not the fastest possible implementation but it
+ * produces bit-identical results to the generic C version so it's
+ * fully "transparent".
+ */
+static void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])
+{
+   /* This is constructed to match our regular (generic) integer IDCT exactly. */
+   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+   __m128i tmp;
+
+   /* dot product constant: even elems=x, odd elems=y */
+   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+   /* out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
+    * out(1) = c1[even]*x + c1[odd]*y
+    */
+   #define dct_rot(out0,out1, x,y,c0,c1) \
+      __m128i c0##lo   = _mm_unpacklo_epi16((x),(y)); \
+      __m128i c0##hi   = _mm_unpackhi_epi16((x),(y)); \
+      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+   /* out = in << 12  (in 16-bit, out 32-bit) */
+   #define dct_widen(out, in) \
+      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+   /* wide add */
+   #define dct_wadd(out, a, b) \
+      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+   /* wide sub */
+   #define dct_wsub(out, a, b) \
+      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+   /* butterfly a/b, add bias, then shift by "s" and pack */
+   #define dct_bfly32o(out0, out1, a,b,bias,s) \
+      { \
+         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+         dct_wadd(sum, abiased, b); \
+         dct_wsub(dif, abiased, b); \
+         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+      }
+
+   /* 8-bit interleave step (for transposes) */
+   #define dct_interleave8(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi8(a, b); \
+      b = _mm_unpackhi_epi8(tmp, b)
+
+   /* 16-bit interleave step (for transposes) */
+   #define dct_interleave16(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi16(a, b); \
+      b = _mm_unpackhi_epi16(tmp, b)
+
+   #define dct_pass(bias,shift) \
+      { \
+         /* even part */ \
+         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+         __m128i sum04 = _mm_add_epi16(row0, row4); \
+         __m128i dif04 = _mm_sub_epi16(row0, row4); \
+         dct_widen(t0e, sum04); \
+         dct_widen(t1e, dif04); \
+         dct_wadd(x0, t0e, t3e); \
+         dct_wsub(x3, t0e, t3e); \
+         dct_wadd(x1, t1e, t2e); \
+         dct_wsub(x2, t1e, t2e); \
+         /* odd part */ \
+         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+         __m128i sum17 = _mm_add_epi16(row1, row7); \
+         __m128i sum35 = _mm_add_epi16(row3, row5); \
+         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+         dct_wadd(x4, y0o, y4o); \
+         dct_wadd(x5, y1o, y5o); \
+         dct_wadd(x6, y2o, y5o); \
+         dct_wadd(x7, y3o, y4o); \
+         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+      }
+
+   __m128i rot0_0 = dct_const(RJPEG_F2F(0.5411961f), RJPEG_F2F(0.5411961f) + RJPEG_F2F(-1.847759065f));
+   __m128i rot0_1 = dct_const(RJPEG_F2F(0.5411961f) + RJPEG_F2F( 0.765366865f), RJPEG_F2F(0.5411961f));
+   __m128i rot1_0 = dct_const(RJPEG_F2F(1.175875602f) + RJPEG_F2F(-0.899976223f), RJPEG_F2F(1.175875602f));
+   __m128i rot1_1 = dct_const(RJPEG_F2F(1.175875602f), RJPEG_F2F(1.175875602f) + RJPEG_F2F(-2.562915447f));
+   __m128i rot2_0 = dct_const(RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 0.298631336f), RJPEG_F2F(-1.961570560f));
+   __m128i rot2_1 = dct_const(RJPEG_F2F(-1.961570560f), RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 3.072711026f));
+   __m128i rot3_0 = dct_const(RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 2.053119869f), RJPEG_F2F(-0.390180644f));
+   __m128i rot3_1 = dct_const(RJPEG_F2F(-0.390180644f), RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 1.501321110f));
+
+   /* rounding biases in column/row passes, see rjpeg_idct_block for explanation. */
+   __m128i bias_0 = _mm_set1_epi32(512);
+   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+   /* load */
+   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+   row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+   /* column pass */
+   dct_pass(bias_0, 10);
+
+   {
+      /* 16bit 8x8 transpose pass 1 */
+      dct_interleave16(row0, row4);
+      dct_interleave16(row1, row5);
+      dct_interleave16(row2, row6);
+      dct_interleave16(row3, row7);
+
+      /* transpose pass 2 */
+      dct_interleave16(row0, row2);
+      dct_interleave16(row1, row3);
+      dct_interleave16(row4, row6);
+      dct_interleave16(row5, row7);
+
+      /* transpose pass 3 */
+      dct_interleave16(row0, row1);
+      dct_interleave16(row2, row3);
+      dct_interleave16(row4, row5);
+      dct_interleave16(row6, row7);
+   }
+
+   /* row pass */
+   dct_pass(bias_1, 17);
+
+   {
+      /* pack */
+      __m128i p0 = _mm_packus_epi16(row0, row1); /* a0a1a2a3...a7b0b1b2b3...b7 */
+      __m128i p1 = _mm_packus_epi16(row2, row3);
+      __m128i p2 = _mm_packus_epi16(row4, row5);
+      __m128i p3 = _mm_packus_epi16(row6, row7);
+
+      /* 8bit 8x8 transpose pass 1 */
+      dct_interleave8(p0, p2); /* a0e0a1e1... */
+      dct_interleave8(p1, p3); /* c0g0c1g1... */
+
+      /* transpose pass 2 */
+      dct_interleave8(p0, p1); /* a0c0e0g0... */
+      dct_interleave8(p2, p3); /* b0d0f0h0... */
+
+      /* transpose pass 3 */
+      dct_interleave8(p0, p2); /* a0b0c0d0... */
+      dct_interleave8(p1, p3); /* a4b4c4d4... */
+
+      /* store */
+      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+   }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif
+
+#ifdef RJPEG_NEON
+
+/* NEON integer IDCT. should produce bit-identical
+ * results to the generic C version. */
+static void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])
+{
+   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+   int16x4_t rot0_0 = vdup_n_s16(RJPEG_F2F(0.5411961f));
+   int16x4_t rot0_1 = vdup_n_s16(RJPEG_F2F(-1.847759065f));
+   int16x4_t rot0_2 = vdup_n_s16(RJPEG_F2F( 0.765366865f));
+   int16x4_t rot1_0 = vdup_n_s16(RJPEG_F2F( 1.175875602f));
+   int16x4_t rot1_1 = vdup_n_s16(RJPEG_F2F(-0.899976223f));
+   int16x4_t rot1_2 = vdup_n_s16(RJPEG_F2F(-2.562915447f));
+   int16x4_t rot2_0 = vdup_n_s16(RJPEG_F2F(-1.961570560f));
+   int16x4_t rot2_1 = vdup_n_s16(RJPEG_F2F(-0.390180644f));
+   int16x4_t rot3_0 = vdup_n_s16(RJPEG_F2F( 0.298631336f));
+   int16x4_t rot3_1 = vdup_n_s16(RJPEG_F2F( 2.053119869f));
+   int16x4_t rot3_2 = vdup_n_s16(RJPEG_F2F( 3.072711026f));
+   int16x4_t rot3_3 = vdup_n_s16(RJPEG_F2F( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+/* wide add */
+#define dct_wadd(out, a, b) \
+   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+/* wide sub */
+#define dct_wsub(out, a, b) \
+   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+/* butterfly a/b, then shift using "shiftop" by "s" and pack */
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+   { \
+      dct_wadd(sum, a, b); \
+      dct_wsub(dif, a, b); \
+      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+   }
+
+#define dct_pass(shiftop, shift) \
+   { \
+      /* even part */ \
+      int16x8_t sum26 = vaddq_s16(row2, row6); \
+      dct_long_mul(p1e, sum26, rot0_0); \
+      dct_long_mac(t2e, p1e, row6, rot0_1); \
+      dct_long_mac(t3e, p1e, row2, rot0_2); \
+      int16x8_t sum04 = vaddq_s16(row0, row4); \
+      int16x8_t dif04 = vsubq_s16(row0, row4); \
+      dct_widen(t0e, sum04); \
+      dct_widen(t1e, dif04); \
+      dct_wadd(x0, t0e, t3e); \
+      dct_wsub(x3, t0e, t3e); \
+      dct_wadd(x1, t1e, t2e); \
+      dct_wsub(x2, t1e, t2e); \
+      /* odd part */ \
+      int16x8_t sum15 = vaddq_s16(row1, row5); \
+      int16x8_t sum17 = vaddq_s16(row1, row7); \
+      int16x8_t sum35 = vaddq_s16(row3, row5); \
+      int16x8_t sum37 = vaddq_s16(row3, row7); \
+      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+      dct_long_mul(p5o, sumodd, rot1_0); \
+      dct_long_mac(p1o, p5o, sum17, rot1_1); \
+      dct_long_mac(p2o, p5o, sum35, rot1_2); \
+      dct_long_mul(p3o, sum37, rot2_0); \
+      dct_long_mul(p4o, sum15, rot2_1); \
+      dct_wadd(sump13o, p1o, p3o); \
+      dct_wadd(sump24o, p2o, p4o); \
+      dct_wadd(sump23o, p2o, p3o); \
+      dct_wadd(sump14o, p1o, p4o); \
+      dct_long_mac(x4, sump13o, row7, rot3_0); \
+      dct_long_mac(x5, sump24o, row5, rot3_1); \
+      dct_long_mac(x6, sump23o, row3, rot3_2); \
+      dct_long_mac(x7, sump14o, row1, rot3_3); \
+      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+   }
+
+   /* load */
+   row0 = vld1q_s16(data + 0*8);
+   row1 = vld1q_s16(data + 1*8);
+   row2 = vld1q_s16(data + 2*8);
+   row3 = vld1q_s16(data + 3*8);
+   row4 = vld1q_s16(data + 4*8);
+   row5 = vld1q_s16(data + 5*8);
+   row6 = vld1q_s16(data + 6*8);
+   row7 = vld1q_s16(data + 7*8);
+
+   /* add DC bias */
+   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+   /* column pass */
+   dct_pass(vrshrn_n_s32, 10);
+
+   /* 16bit 8x8 transpose */
+   {
+/* these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+ * whether compilers actually get this is another story, sadly. */
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+      /* pass 1 */
+      dct_trn16(row0, row1); /* a0b0a2b2a4b4a6b6 */
+      dct_trn16(row2, row3);
+      dct_trn16(row4, row5);
+      dct_trn16(row6, row7);
+
+      /* pass 2 */
+      dct_trn32(row0, row2); /* a0b0c0d0a4b4c4d4 */
+      dct_trn32(row1, row3);
+      dct_trn32(row4, row6);
+      dct_trn32(row5, row7);
+
+      /* pass 3 */
+      dct_trn64(row0, row4); /* a0b0c0d0e0f0g0h0 */
+      dct_trn64(row1, row5);
+      dct_trn64(row2, row6);
+      dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+   }
+
+   /* row pass
+    * vrshrn_n_s32 only supports shifts up to 16, we need
+    * 17. so do a non-rounding shift of 16 first then follow
+    * up with a rounding shift by 1. */
+   dct_pass(vshrn_n_s32, 16);
+
+   {
+      /* pack and round */
+      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+      /* again, these can translate into one instruction, but often don't. */
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+      /* sadly can't use interleaved stores here since we only write
+       * 8 bytes to each scan line! */
+
+      /* 8x8 8-bit transpose pass 1 */
+      dct_trn8_8(p0, p1);
+      dct_trn8_8(p2, p3);
+      dct_trn8_8(p4, p5);
+      dct_trn8_8(p6, p7);
+
+      /* pass 2 */
+      dct_trn8_16(p0, p2);
+      dct_trn8_16(p1, p3);
+      dct_trn8_16(p4, p6);
+      dct_trn8_16(p5, p7);
+
+      /* pass 3 */
+      dct_trn8_32(p0, p4);
+      dct_trn8_32(p1, p5);
+      dct_trn8_32(p2, p6);
+      dct_trn8_32(p3, p7);
+
+      /* store */
+      vst1_u8(out, p0);
+      out += out_stride;
+      vst1_u8(out, p1);
+      out += out_stride;
+      vst1_u8(out, p2);
+      out += out_stride;
+      vst1_u8(out, p3);
+      out += out_stride;
+      vst1_u8(out, p4);
+      out += out_stride;
+      vst1_u8(out, p5);
+      out += out_stride;
+      vst1_u8(out, p6);
+      out += out_stride;
+      vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+   }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif /* RJPEG_NEON */
+
+static uint8_t rjpeg_get_marker(rjpeg_jpeg *j)
+{
+   uint8_t x;
+
+   if (j->marker != RJPEG_MARKER_NONE)
+   {
+      x = j->marker;
+      j->marker = RJPEG_MARKER_NONE;
+      return x;
+   }
+
+   x = rjpeg_get8(j->s);
+   if (x != 0xff)
+      return RJPEG_MARKER_NONE;
+   while (x == 0xff)
+      x = rjpeg_get8(j->s);
+   return x;
+}
+
+/* after a restart interval, rjpeg_jpeg_reset the entropy decoder and
+ * the dc prediction
+ */
+static void rjpeg_jpeg_reset(rjpeg_jpeg *j)
+{
+   j->code_bits           = 0;
+   j->code_buffer         = 0;
+   j->nomore              = 0;
+   j->img_comp[0].dc_pred = 0;
+   j->img_comp[1].dc_pred = 0;
+   j->img_comp[2].dc_pred = 0;
+   j->marker              = RJPEG_MARKER_NONE;
+   j->todo                = j->restart_interval ? j->restart_interval : 0x7fffffff;
+   j->eob_run             = 0;
+
+   /* no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+    * since we don't even allow 1<<30 pixels */
+}
+
+static int rjpeg_parse_entropy_coded_data(rjpeg_jpeg *z)
+{
+   rjpeg_jpeg_reset(z);
+
+   if (z->scan_n == 1)
+   {
+      int i, j;
+      int n = z->order[0];
+      int w = (z->img_comp[n].x+7) >> 3;
+      int h = (z->img_comp[n].y+7) >> 3;
+
+      /* non-interleaved data, we just need to process one block at a time,
+       * in trivial scanline order
+       * number of blocks to do just depends on how many actual "pixels" this
+       * component has, independent of interleaved MCU blocking and such */
+
+      if (z->progressive)
+      {
+         for (j = 0; j < h; ++j)
+         {
+            for (i = 0; i < w; ++i)
+            {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+
+               if (z->spec_start == 0)
+               {
+                  if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                     return 0;
+               }
+               else
+               {
+                  int ha = z->img_comp[n].ha;
+                  if (!rjpeg_jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+                     return 0;
+               }
+
+               /* every data block is an MCU, so countdown the restart interval */
+               if (--z->todo <= 0)
+               {
+                  if (z->code_bits < 24)
+                     rjpeg_grow_buffer_unsafe(z);
+
+                  if (!RJPEG_RESTART(z->marker))
+                     return 1;
+                  rjpeg_jpeg_reset(z);
+               }
+            }
+         }
+      }
+      else
+      {
+         RJPEG_SIMD_ALIGN(short, data[64]);
+
+         for (j = 0; j < h; ++j)
+         {
+            for (i = 0; i < w; ++i)
+            {
+               int ha = z->img_comp[n].ha;
+               if (!rjpeg_jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd,
+                        z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq]))
+                  return 0;
+
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8,
+                     z->img_comp[n].w2, data);
+
+               /* every data block is an MCU, so countdown the restart interval */
+               if (--z->todo <= 0)
+               {
+                  if (z->code_bits < 24)
+                     rjpeg_grow_buffer_unsafe(z);
+
+                  /* if it's NOT a restart, then just bail,
+                   * so we get corrupt data rather than no data */
+                  if (!RJPEG_RESTART(z->marker))
+                     return 1;
+                  rjpeg_jpeg_reset(z);
+               }
+            }
+         }
+      }
+   }
+   else
+   {
+      /* interleaved */
+      int i,j,k,x,y;
+
+      if (z->progressive)
+      {
+         for (j = 0; j < z->img_mcu_y; ++j)
+         {
+            for (i = 0; i < z->img_mcu_x; ++i)
+            {
+               /* scan an interleaved MCU... process scan_n components in order */
+               for (k = 0; k < z->scan_n; ++k)
+               {
+                  int n = z->order[k];
+                  /* scan out an MCU's worth of this component; that's just determined
+                   * by the basic H and V specified for the component */
+                  for (y = 0; y < z->img_comp[n].v; ++y)
+                  {
+                     for (x = 0; x < z->img_comp[n].h; ++x)
+                     {
+                        int      x2 = (i*z->img_comp[n].h + x);
+                        int      y2 = (j*z->img_comp[n].v + y);
+                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+                        if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                           return 0;
+                     }
+                  }
+               }
+
+               /* after all interleaved components, that's an interleaved MCU,
+                * so now count down the restart interval */
+               if (--z->todo <= 0)
+               {
+                  if (z->code_bits < 24)
+                     rjpeg_grow_buffer_unsafe(z);
+                  if (!RJPEG_RESTART(z->marker))
+                     return 1;
+                  rjpeg_jpeg_reset(z);
+               }
+            }
+         }
+      }
+      else
+      {
+         RJPEG_SIMD_ALIGN(short, data[64]);
+
+         for (j = 0; j < z->img_mcu_y; ++j)
+         {
+            for (i = 0; i < z->img_mcu_x; ++i)
+            {
+               /* scan an interleaved MCU... process scan_n components in order */
+               for (k = 0; k < z->scan_n; ++k)
+               {
+                  int n = z->order[k];
+                  /* scan out an MCU's worth of this component; that's just determined
+                   * by the basic H and V specified for the component */
+                  for (y = 0; y < z->img_comp[n].v; ++y)
+                  {
+                     for (x = 0; x < z->img_comp[n].h; ++x)
+                     {
+                        int x2 = (i*z->img_comp[n].h + x)*8;
+                        int y2 = (j*z->img_comp[n].v + y)*8;
+                        int ha = z->img_comp[n].ha;
+
+                        if (!rjpeg_jpeg_decode_block(z, data,
+                                 z->huff_dc+z->img_comp[n].hd,
+                                 z->huff_ac+ha, z->fast_ac[ha],
+                                 n, z->dequant[z->img_comp[n].tq]))
+                           return 0;
+
+                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2,
+                              z->img_comp[n].w2, data);
+                     }
+                  }
+               }
+
+               /* after all interleaved components, that's an interleaved MCU,
+                * so now count down the restart interval */
+               if (--z->todo <= 0)
+               {
+                  if (z->code_bits < 24)
+                     rjpeg_grow_buffer_unsafe(z);
+                  if (!RJPEG_RESTART(z->marker))
+                     return 1;
+                  rjpeg_jpeg_reset(z);
+               }
+            }
+         }
+      }
+   }
+
+   return 1;
+}
+
+static void rjpeg_jpeg_dequantize(short *data, uint8_t *dequant)
+{
+   int i;
+   for (i = 0; i < 64; ++i)
+      data[i] *= dequant[i];
+}
+
+static void rjpeg_jpeg_finish(rjpeg_jpeg *z)
+{
+   int i,j,n;
+
+   if (!z->progressive)
+      return;
+
+   /* dequantize and IDCT the data */
+   for (n = 0; n < z->s->img_n; ++n)
+   {
+      int w = (z->img_comp[n].x+7) >> 3;
+      int h = (z->img_comp[n].y+7) >> 3;
+      for (j = 0; j < h; ++j)
+      {
+         for (i = 0; i < w; ++i)
+         {
+            short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+            rjpeg_jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+            z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8,
+                  z->img_comp[n].w2, data);
+         }
+      }
+   }
+}
+
+static int rjpeg_process_marker(rjpeg_jpeg *z, int m)
+{
+   int L;
+   switch (m)
+   {
+      case RJPEG_MARKER_NONE: /* no marker found */
+         /* Expected marker. Corrupt JPEG? */
+         return 0;
+
+      case 0xDD: /* DRI - specify restart interval */
+
+         /* Bad DRI length. Corrupt JPEG? */
+         if (RJPEG_GET16BE(z->s) != 4)
+            return 0;
+
+         z->restart_interval = RJPEG_GET16BE(z->s);
+         return 1;
+
+      case 0xDB: /* DQT - define quantization table */
+         L = RJPEG_GET16BE(z->s)-2;
+         while (L > 0)
+         {
+            int q = rjpeg_get8(z->s);
+            int p = q >> 4;
+            int t = q & 15,i;
+
+            /* Bad DQT type. Corrupt JPEG? */
+            if (p != 0)
+               return 0;
+
+            /* Bad DQT table. Corrupt JPEG? */
+            if (t > 3)
+               return 0;
+
+            for (i = 0; i < 64; ++i)
+               z->dequant[t][rjpeg_jpeg_dezigzag[i]] = rjpeg_get8(z->s);
+            L -= 65;
+         }
+         return L == 0;
+
+      case 0xC4: /* DHT - define huffman table */
+         L = RJPEG_GET16BE(z->s)-2;
+         while (L > 0)
+         {
+            int sizes[16],i,n = 0;
+            uint8_t *v = NULL;
+            int q      = rjpeg_get8(z->s);
+            int tc     = q >> 4;
+            int th     = q & 15;
+
+            /* Bad DHT header. Corrupt JPEG? */
+            if (tc > 1 || th > 3)
+               return 0;
+
+            for (i = 0; i < 16; ++i)
+            {
+               sizes[i] = rjpeg_get8(z->s);
+               n += sizes[i];
+            }
+            L -= 17;
+
+            if (tc == 0)
+            {
+               if (!rjpeg_build_huffman(z->huff_dc+th, sizes))
+                  return 0;
+               v = z->huff_dc[th].values;
+            }
+            else
+            {
+               if (!rjpeg_build_huffman(z->huff_ac+th, sizes))
+                  return 0;
+               v = z->huff_ac[th].values;
+            }
+            for (i = 0; i < n; ++i)
+               v[i] = rjpeg_get8(z->s);
+            if (tc != 0)
+               rjpeg_build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+            L -= n;
+         }
+         return L == 0;
+   }
+
+   /* check for comment block or APP blocks */
+   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE)
+   {
+      int n = RJPEG_GET16BE(z->s)-2;
+
+      if (n < 0)
+         z->s->img_buffer = z->s->img_buffer_end;
+      else
+         z->s->img_buffer += n;
+
+      return 1;
+   }
+   return 0;
+}
+
+/* after we see SOS */
+static int rjpeg_process_scan_header(rjpeg_jpeg *z)
+{
+   int i;
+   int aa;
+   int Ls    = RJPEG_GET16BE(z->s);
+
+   z->scan_n = rjpeg_get8(z->s);
+
+   /* Bad SOS component count. Corrupt JPEG? */
+   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n)
+      return 0;
+
+   /* Bad SOS length. Corrupt JPEG? */
+   if (Ls != 6+2*z->scan_n)
+      return 0;
+
+   for (i = 0; i < z->scan_n; ++i)
+   {
+      int which;
+      int id = rjpeg_get8(z->s);
+      int q  = rjpeg_get8(z->s);
+
+      for (which = 0; which < z->s->img_n; ++which)
+         if (z->img_comp[which].id == id)
+            break;
+      if (which == z->s->img_n)
+         return 0; /* no match */
+
+      /* Bad DC huff. Corrupt JPEG? */
+      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3)
+         return 0;
+
+      /* Bad AC huff. Corrupt JPEG? */
+      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3)
+         return 0;
+
+      z->order[i] = which;
+   }
+
+   z->spec_start = rjpeg_get8(z->s);
+   z->spec_end   = rjpeg_get8(z->s); /* should be 63, but might be 0 */
+   aa            = rjpeg_get8(z->s);
+   z->succ_high  = (aa >> 4);
+   z->succ_low   = (aa & 15);
+
+   if (z->progressive)
+   {
+      /* Bad SOS. Corrupt JPEG? */
+      if (  z->spec_start > 63 ||
+            z->spec_end > 63   ||
+            z->spec_start > z->spec_end ||
+            z->succ_high > 13           ||
+            z->succ_low > 13)
+         return 0;
+   }
+   else
+   {
+      /* Bad SOS. Corrupt JPEG? */
+      if (z->spec_start != 0)
+         return 0;
+      if (z->succ_high != 0 || z->succ_low != 0)
+         return 0;
+
+      z->spec_end = 63;
+   }
+
+   return 1;
+}
+
+static int rjpeg_process_frame_header(rjpeg_jpeg *z, int scan)
+{
+   rjpeg_context *s = z->s;
+   int Lf,p,i,q, h_max=1,v_max=1,c;
+   Lf = RJPEG_GET16BE(s);
+
+   /* JPEG */
+
+   /* Bad SOF len. Corrupt JPEG? */
+   if (Lf < 11)
+      return 0;
+
+   p  = rjpeg_get8(s);
+
+   /* JPEG baseline */
+
+   /* Only 8-bit. JPEG format not supported? */
+   if (p != 8)
+      return 0;
+
+   s->img_y = RJPEG_GET16BE(s);
+
+   /* Legal, but we don't handle it--but neither does IJG */
+
+   /* No header height, JPEG format not supported? */
+   if (s->img_y == 0)
+      return 0;
+
+   s->img_x = RJPEG_GET16BE(s);
+
+   /* No header width. Corrupt JPEG? */
+   if (s->img_x == 0)
+      return 0;
+
+   c = rjpeg_get8(s);
+
+   /* JFIF requires */
+
+   /* Bad component count. Corrupt JPEG? */
+   if (c != 3 && c != 1)
+      return 0;
+
+   s->img_n = c;
+
+   for (i = 0; i < c; ++i)
+   {
+      z->img_comp[i].data = NULL;
+      z->img_comp[i].linebuf = NULL;
+   }
+
+   /* Bad SOF length. Corrupt JPEG? */
+   if (Lf != 8+3*s->img_n)
+      return 0;
+
+   for (i = 0; i < s->img_n; ++i)
+   {
+      z->img_comp[i].id = rjpeg_get8(s);
+      if (z->img_comp[i].id != i+1)   /* JFIF requires */
+         if (z->img_comp[i].id != i)  /* some version of jpegtran outputs non-JFIF-compliant files! */
+            return 0;
+
+      q                = rjpeg_get8(s);
+      z->img_comp[i].h = (q >> 4);
+
+      /* Bad H. Corrupt JPEG? */
+      if (!z->img_comp[i].h || z->img_comp[i].h > 4)
+         return 0;
+
+      z->img_comp[i].v = q & 15;
+
+      /* Bad V. Corrupt JPEG? */
+      if (!z->img_comp[i].v || z->img_comp[i].v > 4)
+         return 0;
+
+      z->img_comp[i].tq = rjpeg_get8(s);
+
+      /* Bad TQ. Corrupt JPEG? */
+      if (z->img_comp[i].tq > 3)
+         return 0;
+   }
+
+   if (scan != RJPEG_SCAN_LOAD)
+      return 1;
+
+   /* Image too large to decode? */
+   if ((1 << 30) / s->img_x / s->img_n < s->img_y)
+      return 0;
+
+   for (i = 0; i < s->img_n; ++i)
+   {
+      if (z->img_comp[i].h > h_max)
+         h_max = z->img_comp[i].h;
+      if (z->img_comp[i].v > v_max)
+         v_max = z->img_comp[i].v;
+   }
+
+   /* compute interleaved MCU info */
+   z->img_h_max = h_max;
+   z->img_v_max = v_max;
+   z->img_mcu_w = h_max * 8;
+   z->img_mcu_h = v_max * 8;
+   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+   if (z->progressive)
+   {
+      for (i = 0; i < s->img_n; ++i)
+      {
+         /* number of effective pixels (e.g. for non-interleaved MCU) */
+         z->img_comp[i].x        = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+         z->img_comp[i].y        = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+
+         /* to simplify generation, we'll allocate enough memory to decode
+          * the bogus oversized data from using interleaved MCUs and their
+          * big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+          * discard the extra data until colorspace conversion */
+         z->img_comp[i].w2       = z->img_mcu_x * z->img_comp[i].h * 8;
+         z->img_comp[i].h2       = z->img_mcu_y * z->img_comp[i].v * 8;
+         z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
+
+         /* Out of memory? */
+         if (!z->img_comp[i].raw_data)
+         {
+            for (--i; i >= 0; --i)
+            {
+               free(z->img_comp[i].raw_data);
+               z->img_comp[i].data = NULL;
+            }
+
+            return 0;
+         }
+
+         /* align blocks for IDCT using MMX/SSE */
+         z->img_comp[i].data      = (uint8_t*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+         z->img_comp[i].linebuf   = NULL;
+         z->img_comp[i].coeff_w   = (z->img_comp[i].w2 + 7) >> 3;
+         z->img_comp[i].coeff_h   = (z->img_comp[i].h2 + 7) >> 3;
+         z->img_comp[i].raw_coeff = malloc(z->img_comp[i].coeff_w *
+                                    z->img_comp[i].coeff_h * 64 * sizeof(short) + 15);
+         z->img_comp[i].coeff     = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+      }
+   }
+   else
+   {
+      for (i = 0; i < s->img_n; ++i)
+      {
+         /* number of effective pixels (e.g. for non-interleaved MCU) */
+         z->img_comp[i].x        = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+         z->img_comp[i].y        = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+
+         /* to simplify generation, we'll allocate enough memory to decode
+          * the bogus oversized data from using interleaved MCUs and their
+          * big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+          * discard the extra data until colorspace conversion */
+         z->img_comp[i].w2       = z->img_mcu_x * z->img_comp[i].h * 8;
+         z->img_comp[i].h2       = z->img_mcu_y * z->img_comp[i].v * 8;
+         z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
+
+         /* Out of memory? */
+         if (!z->img_comp[i].raw_data)
+         {
+            for (--i; i >= 0; --i)
+            {
+               free(z->img_comp[i].raw_data);
+               z->img_comp[i].data = NULL;
+            }
+         }
+
+         /* align blocks for IDCT using MMX/SSE */
+         z->img_comp[i].data      = (uint8_t*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+         z->img_comp[i].linebuf   = NULL;
+         z->img_comp[i].coeff     = 0;
+         z->img_comp[i].raw_coeff = 0;
+      }
+   }
+
+   return 1;
+}
+
+static int rjpeg_decode_jpeg_header(rjpeg_jpeg *z, int scan)
+{
+   int m;
+   z->marker = RJPEG_MARKER_NONE; /* initialize cached marker to empty */
+   m         = rjpeg_get_marker(z);
+
+   /* No SOI. Corrupt JPEG? */
+   if (m != JPEG_MARKER_SOI)
+      return 0;
+
+   if (scan == RJPEG_SCAN_TYPE)
+      return 1;
+
+   m = rjpeg_get_marker(z);
+   while (!RJPEG_SOF(m))
+   {
+      if (!rjpeg_process_marker(z,m))
+         return 0;
+      m = rjpeg_get_marker(z);
+      while (m == RJPEG_MARKER_NONE)
+      {
+         /* some files have extra padding after their blocks, so ok, we'll scan */
+
+         /* No SOF. Corrupt JPEG? */
+         if (RJPEG_AT_EOF(z->s))
+            return 0;
+
+         m = rjpeg_get_marker(z);
+      }
+   }
+   z->progressive = RJPEG_SOF_PROGRESSIVE(m);
+   if (!rjpeg_process_frame_header(z, scan))
+      return 0;
+   return 1;
+}
+
+/* decode image to YCbCr format */
+static int rjpeg_decode_jpeg_image(rjpeg_jpeg *j)
+{
+   int m;
+   for (m = 0; m < 4; m++)
+   {
+      j->img_comp[m].raw_data = NULL;
+      j->img_comp[m].raw_coeff = NULL;
+   }
+   j->restart_interval = 0;
+   if (!rjpeg_decode_jpeg_header(j, RJPEG_SCAN_LOAD))
+      return 0;
+   m = rjpeg_get_marker(j);
+
+   while (m != JPEG_MARKER_EOI)
+   {
+      if (m == JPEG_MARKER_SOS)
+      {
+         if (!rjpeg_process_scan_header(j))
+            return 0;
+         if (!rjpeg_parse_entropy_coded_data(j))
+            return 0;
+
+         if (j->marker == RJPEG_MARKER_NONE )
+         {
+            /* handle 0s at the end of image data from IP Kamera 9060 */
+
+            while (!RJPEG_AT_EOF(j->s))
+            {
+               int x = rjpeg_get8(j->s);
+               if (x == 255)
+               {
+                  j->marker = rjpeg_get8(j->s);
+                  break;
+               }
+               else if (x != 0) /* Junk before marker. Corrupt JPEG? */
+                  return 0;
+            }
+
+            /* if we reach eof without hitting a marker,
+             * rjpeg_get_marker() below will fail and we'll eventually return 0 */
+         }
+      }
+      else
+      {
+         if (!rjpeg_process_marker(j, m))
+            return 0;
+      }
+      m = rjpeg_get_marker(j);
+   }
+
+   if (j->progressive)
+      rjpeg_jpeg_finish(j);
+   return 1;
+}
+
+/* static jfif-centered resampling (across block boundaries) */
+
+static uint8_t *rjpeg_resample_row_1(uint8_t *out, uint8_t *in_near,
+      uint8_t *in_far, int w, int hs)
+{
+   (void)out;
+   (void)in_far;
+   (void)w;
+   (void)hs;
+   return in_near;
+}
+
+static uint8_t* rjpeg_resample_row_v_2(uint8_t *out, uint8_t *in_near,
+      uint8_t *in_far, int w, int hs)
+{
+   /* need to generate two samples vertically for every one in input */
+   int i;
+   (void)hs;
+   for (i = 0; i < w; ++i)
+      out[i] = RJPEG_DIV4(3*in_near[i] + in_far[i] + 2);
+   return out;
+}
+
+static uint8_t*  rjpeg_resample_row_h_2(uint8_t *out, uint8_t *in_near,
+      uint8_t *in_far, int w, int hs)
+{
+   /* need to generate two samples horizontally for every one in input */
+   int i;
+   uint8_t *input = in_near;
+
+   if (w == 1)
+   {
+      /* if only one sample, can't do any interpolation */
+      out[0] = out[1] = input[0];
+      return out;
+   }
+
+   out[0] = input[0];
+   out[1] = RJPEG_DIV4(input[0]*3 + input[1] + 2);
+
+   for (i=1; i < w-1; ++i)
+   {
+      int n      = 3 * input[i] + 2;
+      out[i*2+0] = RJPEG_DIV4(n+input[i-1]);
+      out[i*2+1] = RJPEG_DIV4(n+input[i+1]);
+   }
+   out[i*2+0] = RJPEG_DIV4(input[w-2]*3 + input[w-1] + 2);
+   out[i*2+1] = input[w-1];
+
+   (void)in_far;
+   (void)hs;
+
+   return out;
+}
+
+static uint8_t *rjpeg_resample_row_hv_2(uint8_t *out, uint8_t *in_near,
+      uint8_t *in_far, int w, int hs)
+{
+   /* need to generate 2x2 samples for every one in input */
+   int i,t0,t1;
+   if (w == 1)
+   {
+      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1     = 3*in_near[0] + in_far[0];
+   out[0] = RJPEG_DIV4(t1+2);
+
+   for (i = 1; i < w; ++i)
+   {
+      t0         = t1;
+      t1         = 3*in_near[i]+in_far[i];
+      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);
+      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = RJPEG_DIV4(t1+2);
+
+   (void)hs;
+
+   return out;
+}
+
+#if defined(__SSE2__) || defined(RJPEG_NEON)
+static uint8_t *rjpeg_resample_row_hv_2_simd(uint8_t *out, uint8_t *in_near,
+      uint8_t *in_far, int w, int hs)
+{
+   /* need to generate 2x2 samples for every one in input */
+   int i = 0,t0,t1;
+
+   if (w == 1)
+   {
+      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   /* process groups of 8 pixels for as long as we can.
+    * note we can't handle the last pixel in a row in this loop
+    * because we need to handle the filter boundary conditions.
+    */
+   for (; i < ((w-1) & ~7); i += 8)
+   {
+#if defined(__SSE2__)
+      /* load and perform the vertical filtering pass
+       * this uses 3*x + y = 4*x + (y - x) */
+      __m128i zero  = _mm_setzero_si128();
+      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
+      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
+      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+      __m128i diff  = _mm_sub_epi16(farw, nearw);
+      __m128i nears = _mm_slli_epi16(nearw, 2);
+      __m128i curr  = _mm_add_epi16(nears, diff); /* current row */
+
+      /* horizontal filter works the same based on shifted vers of current
+       * row. "prev" is current row shifted right by 1 pixel; we need to
+       * insert the previous pixel value (from t1).
+       * "next" is current row shifted left by 1 pixel, with first pixel
+       * of next block of 8 pixels added in.
+       */
+      __m128i prv0 = _mm_slli_si128(curr, 2);
+      __m128i nxt0 = _mm_srli_si128(curr, 2);
+      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+      /* horizontal filter, polyphase implementation since it's convenient:
+       * even pixels = 3*cur + prev = cur*4 + (prev - cur)
+       * odd  pixels = 3*cur + next = cur*4 + (next - cur)
+       * note the shared term. */
+      __m128i bias = _mm_set1_epi16(8);
+      __m128i curs = _mm_slli_epi16(curr, 2);
+      __m128i prvd = _mm_sub_epi16(prev, curr);
+      __m128i nxtd = _mm_sub_epi16(next, curr);
+      __m128i curb = _mm_add_epi16(curs, bias);
+      __m128i even = _mm_add_epi16(prvd, curb);
+      __m128i odd  = _mm_add_epi16(nxtd, curb);
+
+      /* interleave even and odd pixels, then undo scaling. */
+      __m128i int0 = _mm_unpacklo_epi16(even, odd);
+      __m128i int1 = _mm_unpackhi_epi16(even, odd);
+      __m128i de0  = _mm_srli_epi16(int0, 4);
+      __m128i de1  = _mm_srli_epi16(int1, 4);
+
+      /* pack and write output */
+      __m128i outv = _mm_packus_epi16(de0, de1);
+      _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(RJPEG_NEON)
+      /* load and perform the vertical filtering pass
+       * this uses 3*x + y = 4*x + (y - x) */
+      uint8x8_t farb  = vld1_u8(in_far + i);
+      uint8x8_t nearb = vld1_u8(in_near + i);
+      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+      int16x8_t curr  = vaddq_s16(nears, diff); /* current row */
+
+      /* horizontal filter works the same based on shifted vers of current
+       * row. "prev" is current row shifted right by 1 pixel; we need to
+       * insert the previous pixel value (from t1).
+       * "next" is current row shifted left by 1 pixel, with first pixel
+       * of next block of 8 pixels added in. */
+      int16x8_t prv0 = vextq_s16(curr, curr, 7);
+      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+      /* horizontal filter, polyphase implementation since it's convenient:
+       * even pixels = 3*cur + prev = cur*4 + (prev - cur)
+       * odd  pixels = 3*cur + next = cur*4 + (next - cur)
+       * note the shared term.
+       */
+      int16x8_t curs = vshlq_n_s16(curr, 2);
+      int16x8_t prvd = vsubq_s16(prev, curr);
+      int16x8_t nxtd = vsubq_s16(next, curr);
+      int16x8_t even = vaddq_s16(curs, prvd);
+      int16x8_t odd  = vaddq_s16(curs, nxtd);
+
+      /* undo scaling and round, then store with even/odd phases interleaved */
+      uint8x8x2_t o;
+      o.val[0] = vqrshrun_n_s16(even, 4);
+      o.val[1] = vqrshrun_n_s16(odd,  4);
+      vst2_u8(out + i*2, o);
+#endif
+
+      /* "previous" value for next iteration */
+      t1 = 3*in_near[i+7] + in_far[i+7];
+   }
+
+   t0       = t1;
+   t1       = 3*in_near[i] + in_far[i];
+   out[i*2] = RJPEG_DIV16(3*t1 + t0 + 8);
+
+   for (++i; i < w; ++i)
+   {
+      t0         = t1;
+      t1         = 3*in_near[i]+in_far[i];
+      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);
+      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);
+   }
+   out[w*2-1]    = RJPEG_DIV4(t1+2);
+
+   (void)hs;
+
+   return out;
+}
+#endif
+
+static uint8_t *rjpeg_resample_row_generic(uint8_t *out,
+      uint8_t *in_near, uint8_t *in_far, int w, int hs)
+{
+   /* resample with nearest-neighbor */
+   int i,j;
+   (void)in_far;
+
+   for (i = 0; i < w; ++i)
+      for (j = 0; j < hs; ++j)
+         out[i*hs+j] = in_near[i];
+   return out;
+}
+
+/* this is a reduced-precision calculation of YCbCr-to-RGB introduced
+ * to make sure the code produces the same results in both SIMD and scalar */
+#ifndef FLOAT2FIXED
+#define FLOAT2FIXED(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)
+#endif
+
+static void rjpeg_YCbCr_to_RGB_row(uint8_t *out, const uint8_t *y,
+      const uint8_t *pcb, const uint8_t *pcr, int count, int step)
+{
+   int i;
+   for (i = 0; i < count; ++i)
+   {
+      int y_fixed = (y[i] << 20) + (1<<19); /* rounding */
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      int r = y_fixed +  cr* FLOAT2FIXED(1.40200f);
+      int g = y_fixed + (cr*-FLOAT2FIXED(0.71414f)) + ((cb*-FLOAT2FIXED(0.34414f)) & 0xffff0000);
+      int b = y_fixed                               +   cb* FLOAT2FIXED(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255)
+         r = 255;
+      if ((unsigned) g > 255)
+         g = 255;
+      if ((unsigned) b > 255)
+         b = 255;
+      out[0] = (uint8_t)r;
+      out[1] = (uint8_t)g;
+      out[2] = (uint8_t)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+
+#if defined(__SSE2__) || defined(RJPEG_NEON)
+static void rjpeg_YCbCr_to_RGB_simd(uint8_t *out, const uint8_t *y,
+      const uint8_t *pcb, const uint8_t *pcr, int count, int step)
+{
+   int i = 0;
+
+#if defined(__SSE2__)
+   /* step == 3 is pretty ugly on the final interleave, and i'm not convinced
+    * it's useful in practice (you wouldn't use it for textures, for example).
+    * so just accelerate step == 4 case.
+    */
+   if (step == 4)
+   {
+      /* this is a fairly straightforward implementation and not super-optimized. */
+      __m128i signflip  = _mm_set1_epi8(-0x80);
+      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
+      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
+      __m128i y_bias    = _mm_set1_epi8((char) (unsigned char) 128);
+      __m128i xw        = _mm_set1_epi16(255); /* alpha channel */
+
+      for (; i+7 < count; i += 8)
+      {
+         /* load */
+         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); /* -128 */
+         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); /* -128 */
+
+         /* unpack to short (and left-shift cr, cb by 8) */
+         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
+         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+         /* color transform */
+         __m128i yws = _mm_srli_epi16(yw, 4);
+         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+         __m128i rws = _mm_add_epi16(cr0, yws);
+         __m128i gwt = _mm_add_epi16(cb0, yws);
+         __m128i bws = _mm_add_epi16(yws, cb1);
+         __m128i gws = _mm_add_epi16(gwt, cr1);
+
+         /* descale */
+         __m128i rw = _mm_srai_epi16(rws, 4);
+         __m128i bw = _mm_srai_epi16(bws, 4);
+         __m128i gw = _mm_srai_epi16(gws, 4);
+
+         /* back to byte, set up for transpose */
+         __m128i brb = _mm_packus_epi16(rw, bw);
+         __m128i gxb = _mm_packus_epi16(gw, xw);
+
+         /* transpose to interleave channels */
+         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+         __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+         /* store */
+         _mm_storeu_si128((__m128i *) (out + 0), o0);
+         _mm_storeu_si128((__m128i *) (out + 16), o1);
+         out += 32;
+      }
+   }
+#endif
+
+#ifdef RJPEG_NEON
+   /* in this version, step=3 support would be easy to add. but is there demand? */
+   if (step == 4)
+   {
+      /* this is a fairly straightforward implementation and not super-optimized. */
+      uint8x8_t signflip = vdup_n_u8(0x80);
+      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
+      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));
+
+      for (; i+7 < count; i += 8)
+      {
+         uint8x8x4_t o;
+
+         /* load */
+         uint8x8_t y_bytes  = vld1_u8(y + i);
+         uint8x8_t cr_bytes = vld1_u8(pcr + i);
+         uint8x8_t cb_bytes = vld1_u8(pcb + i);
+         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+         /* expand to s16 */
+         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+         int16x8_t crw = vshll_n_s8(cr_biased, 7);
+         int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+         /* color transform */
+         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+         int16x8_t rws = vaddq_s16(yws, cr0);
+         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+         int16x8_t bws = vaddq_s16(yws, cb1);
+
+         /* undo scaling, round, convert to byte */
+         o.val[0] = vqrshrun_n_s16(rws, 4);
+         o.val[1] = vqrshrun_n_s16(gws, 4);
+         o.val[2] = vqrshrun_n_s16(bws, 4);
+         o.val[3] = vdup_n_u8(255);
+
+         /* store, interleaving r/g/b/a */
+         vst4_u8(out, o);
+         out += 8*4;
+      }
+   }
+#endif
+
+   for (; i < count; ++i)
+   {
+      int y_fixed = (y[i] << 20) + (1<<19); /* rounding */
+      int cr      = pcr[i] - 128;
+      int cb      = pcb[i] - 128;
+      int r       = y_fixed + cr* FLOAT2FIXED(1.40200f);
+      int g       = y_fixed + cr*-FLOAT2FIXED(0.71414f) + ((cb*-FLOAT2FIXED(0.34414f)) & 0xffff0000);
+      int b       = y_fixed                             +   cb* FLOAT2FIXED(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255)
+         r = 255;
+      if ((unsigned) g > 255)
+         g = 255;
+      if ((unsigned) b > 255)
+         b = 255;
+      out[0] = (uint8_t)r;
+      out[1] = (uint8_t)g;
+      out[2] = (uint8_t)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#endif
+
+/* set up the kernels */
+static void rjpeg_setup_jpeg(rjpeg_jpeg *j)
+{
+   uint64_t mask = cpu_features_get();
+
+   (void)mask;
+
+   j->idct_block_kernel        = rjpeg_idct_block;
+   j->YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_row;
+   j->resample_row_hv_2_kernel = rjpeg_resample_row_hv_2;
+
+#if defined(__SSE2__)
+   if (mask & RETRO_SIMD_SSE2)
+   {
+      j->idct_block_kernel        = rjpeg_idct_simd;
+      j->YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_simd;
+      j->resample_row_hv_2_kernel = rjpeg_resample_row_hv_2_simd;
+   }
+#endif
+
+#ifdef RJPEG_NEON
+   j->idct_block_kernel           = rjpeg_idct_simd;
+   j->YCbCr_to_RGB_kernel         = rjpeg_YCbCr_to_RGB_simd;
+   j->resample_row_hv_2_kernel    = rjpeg_resample_row_hv_2_simd;
+#endif
+}
+
+/* clean up the temporary component buffers */
+static void rjpeg_cleanup_jpeg(rjpeg_jpeg *j)
+{
+   int i;
+   for (i = 0; i < j->s->img_n; ++i)
+   {
+      if (j->img_comp[i].raw_data)
+      {
+         free(j->img_comp[i].raw_data);
+         j->img_comp[i].raw_data = NULL;
+         j->img_comp[i].data = NULL;
+      }
+
+      if (j->img_comp[i].raw_coeff)
+      {
+         free(j->img_comp[i].raw_coeff);
+         j->img_comp[i].raw_coeff = 0;
+         j->img_comp[i].coeff = 0;
+      }
+
+      if (j->img_comp[i].linebuf)
+      {
+         free(j->img_comp[i].linebuf);
+         j->img_comp[i].linebuf = NULL;
+      }
+   }
+}
+
+static uint8_t *rjpeg_load_jpeg_image(rjpeg_jpeg *z,
+      unsigned *out_x, unsigned *out_y, int *comp, int req_comp)
+{
+   int n, decode_n;
+   int k;
+   unsigned int i,j;
+   rjpeg_resample res_comp[4];
+   uint8_t *coutput[4] = {0};
+   uint8_t *output     = NULL;
+   z->s->img_n         = 0;
+
+   /* load a jpeg image from whichever source, but leave in YCbCr format */
+   if (!rjpeg_decode_jpeg_image(z))
+      goto error;
+
+   /* determine actual number of components to generate */
+   n = req_comp ? req_comp : z->s->img_n;
+
+   if (z->s->img_n == 3 && n < 3)
+      decode_n = 1;
+   else
+      decode_n = z->s->img_n;
+
+   /* resample and color-convert */
+   for (k = 0; k < decode_n; ++k)
+   {
+      rjpeg_resample *r = &res_comp[k];
+
+      /* allocate line buffer big enough for upsampling off the edges
+       * with upsample factor of 4 */
+      z->img_comp[k].linebuf = (uint8_t *) malloc(z->s->img_x + 3);
+      if (!z->img_comp[k].linebuf)
+         goto error;
+
+      r->hs       = z->img_h_max / z->img_comp[k].h;
+      r->vs       = z->img_v_max / z->img_comp[k].v;
+      r->ystep    = r->vs >> 1;
+      r->w_lores  = (z->s->img_x + r->hs-1) / r->hs;
+      r->ypos     = 0;
+      r->line0    = r->line1 = z->img_comp[k].data;
+      r->resample = rjpeg_resample_row_generic;
+
+      if      (r->hs == 1 && r->vs == 1)
+         r->resample = rjpeg_resample_row_1;
+      else if (r->hs == 1 && r->vs == 2)
+         r->resample = rjpeg_resample_row_v_2;
+      else if (r->hs == 2 && r->vs == 1)
+         r->resample = rjpeg_resample_row_h_2;
+      else if (r->hs == 2 && r->vs == 2)
+         r->resample = z->resample_row_hv_2_kernel;
+   }
+
+   /* can't error after this so, this is safe */
+   output = (uint8_t *) malloc(n * z->s->img_x * z->s->img_y + 1);
+
+   if (!output)
+      goto error;
+
+   /* now go ahead and resample */
+   for (j = 0; j < z->s->img_y; ++j)
+   {
+      uint8_t *out = output + n * z->s->img_x * j;
+      for (k = 0; k < decode_n; ++k)
+      {
+         rjpeg_resample *r = &res_comp[k];
+         int         y_bot  = r->ystep >= (r->vs >> 1);
+
+         coutput[k]         = r->resample(z->img_comp[k].linebuf,
+               y_bot ? r->line1 : r->line0,
+               y_bot ? r->line0 : r->line1,
+               r->w_lores, r->hs);
+
+         if (++r->ystep >= r->vs)
+         {
+            r->ystep = 0;
+            r->line0 = r->line1;
+            if (++r->ypos < z->img_comp[k].y)
+               r->line1 += z->img_comp[k].w2;
+         }
+      }
+
+      if (n >= 3)
+      {
+         uint8_t *y = coutput[0];
+         if (y)
+         {
+            if (z->s->img_n == 3)
+               z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+            else
+               for (i = 0; i < z->s->img_x; ++i)
+               {
+                  out[0]  = out[1] = out[2] = y[i];
+                  out[3]  = 255; /* not used if n==3 */
+                  out    += n;
+               }
+         }
+      }
+      else
+      {
+         uint8_t *y = coutput[0];
+         if (n == 1)
+            for (i = 0; i < z->s->img_x; ++i)
+               out[i] = y[i];
+         else
+            for (i = 0; i < z->s->img_x; ++i)
+            {
+               *out++ = y[i];
+               *out++ = 255;
+            }
+      }
+   }
+
+   rjpeg_cleanup_jpeg(z);
+   *out_x = z->s->img_x;
+   *out_y = z->s->img_y;
+
+   if (comp)
+      *comp  = z->s->img_n; /* report original components, not output */
+   return output;
+
+error:
+   rjpeg_cleanup_jpeg(z);
+   return NULL;
+}
+
+int rjpeg_process_image(rjpeg_t *rjpeg, void **buf_data,
+      size_t size, unsigned *width, unsigned *height)
+{
+   rjpeg_jpeg j;
+   rjpeg_context s;
+   int comp;
+   uint32_t *img         = NULL;
+   uint32_t *pixels      = NULL;
+   unsigned size_tex     = 0;
+
+   if (!rjpeg)
+      return IMAGE_PROCESS_ERROR;
+
+   s.img_buffer          = (uint8_t*)rjpeg->buff_data;
+   s.img_buffer_original = (uint8_t*)rjpeg->buff_data;
+   s.img_buffer_end      = (uint8_t*)rjpeg->buff_data + (int)size;
+
+   j.s                   = &s;
+
+   rjpeg_setup_jpeg(&j);
+
+   img                   =  (uint32_t*)rjpeg_load_jpeg_image(&j, width, height, &comp, 4);
+
+   if (!img)
+      return IMAGE_PROCESS_ERROR;
+
+   size_tex = (*width) * (*height);
+   pixels   = (uint32_t*)malloc(size_tex * sizeof(uint32_t));
+
+   if (!pixels)
+   {
+      free(img);
+      return IMAGE_PROCESS_ERROR;
+   }
+
+   *buf_data = pixels;
+
+   /* Convert RGBA to ARGB */
+   while (size_tex--)
+   {
+      unsigned int texel = img[size_tex];
+      unsigned int A     = texel & 0xFF000000;
+      unsigned int B     = texel & 0x00FF0000;
+      unsigned int G     = texel & 0x0000FF00;
+      unsigned int R     = texel & 0x000000FF;
+      ((unsigned int*)pixels)[size_tex] = A | (R << 16) | G | (B >> 16);
+   }
+
+   free(img);
+
+   return IMAGE_PROCESS_END;
+}
+
+bool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data)
+{
+   if (!rjpeg)
+      return false;
+
+   rjpeg->buff_data = (uint8_t*)data;
+
+   return true;
+}
+
+void rjpeg_free(rjpeg_t *rjpeg)
+{
+   if (!rjpeg)
+      return;
+
+   free(rjpeg);
+}
+
+rjpeg_t *rjpeg_alloc(void)
+{
+   rjpeg_t *rjpeg = (rjpeg_t*)calloc(1, sizeof(*rjpeg));
+   if (!rjpeg)
+      return NULL;
+   return rjpeg;
+}
diff --git a/deps/libretro-common/formats/json/rjson.c b/deps/libretro-common/formats/json/rjson.c
new file mode 100644 (file)
index 0000000..f0d73e4
--- /dev/null
@@ -0,0 +1,1568 @@
+/* Copyright  (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rjson.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* The parser is based on Public Domain JSON Parser for C by Christopher Wellons - https://github.com/skeeto/pdjson */
+
+#include <stdio.h>  /* snprintf, vsnprintf */
+#include <stdarg.h> /* va_list */
+#include <string.h> /* memcpy */
+#include <stdint.h> /* int64_t */
+#include <stdlib.h> /* malloc, realloc, atof, atoi */
+
+#include <formats/rjson.h>
+#include <compat/posix_string.h>
+#include <streams/interface_stream.h>
+#include <streams/file_stream.h>
+
+struct _rjson_stack { enum rjson_type type; size_t count; };
+
+struct rjson
+{
+   /* Order of the top few struct elements have an impact on performance */
+   /* Place most frequently accessed things on top */
+   const unsigned char *input_p;
+   struct _rjson_stack *stack_top;
+   const unsigned char *input_end;
+   const unsigned char* source_column_p;
+   size_t source_line;
+
+   char *string, *string_pass_through;
+   size_t string_len, string_cap;
+
+   struct _rjson_stack inline_stack[10];
+   struct _rjson_stack *stack;
+
+   rjson_io_t io;
+   void *user_data;
+
+   unsigned int stack_cap, stack_max;
+   int input_len;
+
+   char option_flags;
+   char decimal_sep;
+   char error_text[80];
+   char inline_string[512];
+
+   /* Must be at the end of the struct, can be allocated with custom size */
+   unsigned char input_buf[512];
+};
+
+enum _rjson_token
+{
+   _rJSON_TOK_WHITESPACE, _rJSON_TOK_NEWLINE, _rJSON_TOK_OPTIONAL_SKIP,
+   _rJSON_TOK_OBJECT, _rJSON_TOK_ARRAY, _rJSON_TOK_STRING, _rJSON_TOK_NUMBER,
+   _rJSON_TOK_TRUE, _rJSON_TOK_FALSE, _rJSON_TOK_NULL,
+   _rJSON_TOK_OBJECT_END, _rJSON_TOK_ARRAY_END, _rJSON_TOK_COLON,
+   _rJSON_TOK_COMMA, _rJSON_TOK_ERROR, _rJSON_TOK_EOF, _rJSON_TOKCOUNT
+};
+
+/* The used char type is int and not short for better performance */
+typedef unsigned int _rjson_char_t;
+#define _rJSON_EOF ((_rjson_char_t)256)
+
+/* Compiler branching hint for expression with high probability
+ * Explicitly only have likely (and no unlikely) because compilers
+ * that don't support it expect likely branches to come first. */
+#if defined(__GNUC__) || defined(__clang__)
+#define _rJSON_LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define _rJSON_LIKELY(x) (x)
+#endif
+
+/* These 3 error functions return RJSON_ERROR for convenience */
+static enum rjson_type _rjson_error(rjson_t *json, const char *fmt, ...)
+{
+   va_list ap;
+   if (json->stack_top->type == RJSON_ERROR)
+      return RJSON_ERROR;
+   json->stack_top->type = RJSON_ERROR;
+   va_start(ap, fmt);
+   vsnprintf(json->error_text, sizeof(json->error_text), fmt, ap);
+   va_end(ap);
+   return RJSON_ERROR;
+}
+
+static enum rjson_type _rjson_error_char(rjson_t *json,
+      const char *fmt, _rjson_char_t chr)
+{
+   char buf[16];
+   if (json->stack_top->type == RJSON_ERROR)
+      return RJSON_ERROR;
+   snprintf(buf, sizeof(buf),
+         (chr == _rJSON_EOF ? "end of stream" :
+         (chr >= ' ' && chr <= '~' ? "'%c'" : "byte 0x%02X")), chr);
+   return _rjson_error(json, fmt, buf);
+}
+
+static enum rjson_type _rjson_error_token(rjson_t *json,
+   const char *fmt, enum _rjson_token tok)
+{
+   return _rjson_error_char(json, fmt,
+         (tok == _rJSON_TOK_EOF ? _rJSON_EOF : json->input_p[-1]));
+}
+
+static bool _rjson_io_input(rjson_t *json)
+{
+   if (json->input_end == json->input_buf)
+      return false;
+   json->source_column_p -= (json->input_end - json->input_buf);
+   json->input_p = json->input_buf;
+   json->input_end = json->input_buf +
+         json->io(json->input_buf, json->input_len, json->user_data);
+   if (json->input_end < json->input_buf)
+   {
+      _rjson_error(json, "input stream read error");
+      json->input_end = json->input_buf;
+   }
+   return (json->input_end != json->input_p);
+}
+
+static bool _rjson_grow_string(rjson_t *json)
+{
+   char *string;
+   size_t new_string_cap = json->string_cap * 2;
+   if (json->string != json->inline_string)
+      string             = (char*)realloc(json->string, new_string_cap);
+   else if ((string      = (char*)malloc(new_string_cap)) != NULL)
+      memcpy(string, json->inline_string, sizeof(json->inline_string));
+   if (!string)
+   {
+      _rjson_error(json, "out of memory");
+      return false;
+   }
+   json->string_cap      = new_string_cap;
+   json->string          = string;
+   return true;
+}
+
+static INLINE bool _rjson_pushchar(rjson_t *json, _rjson_char_t c)
+{
+   json->string[json->string_len++] = (char)c;
+   return (json->string_len != json->string_cap || _rjson_grow_string(json));
+}
+
+static INLINE bool _rjson_pushchars(rjson_t *json,
+      const unsigned char *from, const unsigned char *to)
+{
+   size_t len = json->string_len, new_len = len + (to - from);
+   unsigned char* string;
+   while (new_len >= json->string_cap)
+      if (!_rjson_grow_string(json))
+         return false;
+   string = (unsigned char *)json->string;
+   while (len != new_len)
+      string[len++] = *(from++);
+   json->string_len = new_len;
+   return true;
+}
+
+static INLINE _rjson_char_t _rjson_char_get(rjson_t *json)
+{
+   return (json->input_p != json->input_end || _rjson_io_input(json)
+        ? *json->input_p++ : _rJSON_EOF);
+}
+
+static unsigned int _rjson_get_unicode_cp(rjson_t *json)
+{
+   unsigned int cp = 0, shift = 16;
+   for (;;)
+   {
+      _rjson_char_t c = _rjson_char_get(json);
+      switch (c)
+      {
+         case '0': case '1': case '2': case '3': case '4':
+         case '5': case '6': case '7': case '8': case '9':
+            c -= '0';
+            break;
+         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+            c -= ('a' - 10);
+            break;
+         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+            c -= ('A' - 10);
+            break;
+         case _rJSON_EOF:
+            _rjson_error(json, "unterminated string literal in Unicode");
+            return (unsigned int)-1;
+         default:
+            _rjson_error_char(json, "invalid Unicode escape hexadecimal %s", c);
+            return (unsigned int)-1;
+      }
+      shift -= 4;
+      cp |= ((unsigned int)c << shift);
+      if (!shift)
+         return cp;
+   }
+}
+
+static bool _rjson_read_unicode(rjson_t *json)
+{
+   #define _rJSON_READ_UNICODE_REPLACE_OR_IGNORE \
+      if (json->option_flags & (RJSON_OPTION_IGNORE_INVALID_ENCODING \
+            | RJSON_OPTION_REPLACE_INVALID_ENCODING)) goto replace_or_ignore;
+
+   unsigned int cp;
+
+   if ((cp = _rjson_get_unicode_cp(json)) == (unsigned int)-1)
+      return false;
+
+   if (cp >= 0xd800 && cp <= 0xdbff)
+   {
+      /* This is the high portion of a surrogate pair; we need to read the
+       * lower portion to get the codepoint */
+      unsigned int l, h = cp;
+
+      _rjson_char_t c = _rjson_char_get(json);
+      if (c == _rJSON_EOF)
+      {
+         _rjson_error(json, "unterminated string literal in Unicode");
+         return false;
+      }
+      if (c != '\\')
+      {
+         _rjson_error_char(json, "invalid continuation %s"
+               " for surrogate pair, expected '\\'", c);
+         return false;
+      }
+
+      c = _rjson_char_get(json);
+      if (c == _rJSON_EOF)
+      {
+         _rjson_error(json, "unterminated string literal in Unicode");
+         return false;
+      }
+      if (c != 'u')
+      {
+         _rjson_error_char(json, "invalid continuation %s"
+               " for surrogate pair, expected 'u'", c);
+         return false;
+      }
+      if ((l = _rjson_get_unicode_cp(json)) == (unsigned int)-1)
+         return false;
+      if (l < 0xdc00 || l > 0xdfff)
+      {
+         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
+         _rjson_error(json, "surrogate pair continuation \\u%04x out "
+            "of range (dc00-dfff)", l);
+         return false;
+      }
+      cp = ((h - 0xd800) * 0x400) + ((l - 0xdc00) + 0x10000);
+   }
+   else if (cp >= 0xdc00 && cp <= 0xdfff)
+   {
+      _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
+      _rjson_error(json, "dangling surrogate \\u%04x", cp);
+      return false;
+   }
+
+   if (cp < 0x80UL)
+      return _rjson_pushchar(json, cp);
+
+   if (cp < 0x0800UL)
+      return (_rjson_pushchar(json, (cp >> 6 & 0x1F) | 0xC0) &&
+              _rjson_pushchar(json, (cp >> 0 & 0x3F) | 0x80));
+
+   if (cp < 0x010000UL)
+   {
+      if (cp >= 0xd800 && cp <= 0xdfff)
+      {
+         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
+         _rjson_error(json, "invalid codepoint %04x", cp);
+         return false;
+      }
+      return (_rjson_pushchar(json, (cp >> 12 & 0x0F) | 0xE0) &&
+              _rjson_pushchar(json, (cp >>  6 & 0x3F) | 0x80) &&
+              _rjson_pushchar(json, (cp >>  0 & 0x3F) | 0x80));
+   }
+   if (cp < 0x110000UL)
+      return (_rjson_pushchar(json, (cp >> 18 & 0x07) | 0xF0) &&
+              _rjson_pushchar(json, (cp >> 12 & 0x3F) | 0x80) &&
+              _rjson_pushchar(json, (cp >>  6 & 0x3F) | 0x80) &&
+              _rjson_pushchar(json, (cp >>  0 & 0x3F) | 0x80));
+
+   _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
+   _rjson_error(json, "unable to encode %04x as UTF-8", cp);
+   return false;
+
+replace_or_ignore:
+   return ((json->option_flags & RJSON_OPTION_IGNORE_INVALID_ENCODING) ||
+         _rjson_pushchar(json, '?'));
+   #undef _rJSON_READ_UNICODE_REPLACE_OR_IGNORE
+}
+
+static bool _rjson_validate_utf8(rjson_t *json)
+{
+   unsigned char first, c;
+   unsigned char *p;
+   unsigned char *from = (unsigned char *)
+         (json->string_pass_through ? json->string_pass_through : json->string);
+   unsigned char *to = from + json->string_len;
+
+   if (json->option_flags & RJSON_OPTION_IGNORE_INVALID_ENCODING)
+      return true;
+
+   for (;;)
+   {
+      if (from == to)
+         return true;
+      first = *from;
+      if (first <= 0x7F) /* ASCII */
+      {
+         from++;
+         continue;
+      }
+      p = from;
+      /* Continuation or overlong encoding of an ASCII byte */
+      if (first <= 0xC1)
+         goto invalid_utf8;
+      if (first <= 0xDF)
+      {
+         if ((from = p + 2) > to)
+            goto invalid_utf8;
+continue_length_2:
+         c = p[1];
+         switch (first)
+         {
+            case 0xE0:
+               c = (c < 0xA0 || c > 0xBF);
+               break;
+            case 0xED:
+               c = (c < 0x80 || c > 0x9F);
+               break;
+            case 0xF0:
+               c = (c < 0x90 || c > 0xBF);
+               break;
+            case 0xF4:
+               c = (c < 0x80 || c > 0x8F);
+               break;
+            default:
+               c = (c < 0x80 || c > 0xBF);
+               break;
+         }
+         if (c)
+            goto invalid_utf8;
+      }
+      else if (first <= 0xEF)
+      {
+         if ((from = p + 3) > to)
+            goto invalid_utf8;
+continue_length_3:
+         if ((c = p[2]) < 0x80 || c > 0xBF)
+            goto invalid_utf8;
+         goto continue_length_2;
+      }
+      else if (first <= 0xF4)
+      {
+         if ((from = p + 4) > to)
+            goto invalid_utf8;
+         if ((c = p[3]) < 0x80 || c > 0xBF)
+            goto invalid_utf8;
+         goto continue_length_3;
+      }
+      else
+         goto invalid_utf8; /* length 5 or 6 or invalid UTF-8 */
+      continue;
+invalid_utf8:
+      if (!(json->option_flags & RJSON_OPTION_REPLACE_INVALID_ENCODING))
+      {
+         _rjson_error(json, "invalid UTF-8 character in string");
+         return false;
+      }
+      from    = p;
+      *from++ = '?';
+      while (from != to && (*from & 0x80))
+         *from++ = '?';
+   }
+}
+
+static enum rjson_type _rjson_read_string(rjson_t *json)
+{
+   const unsigned char *p    = json->input_p, *raw = p;
+   const unsigned char *end  = json->input_end;
+   unsigned char utf8mask    = 0;
+   json->string_pass_through = NULL;
+   json->string_len          = 0;
+
+   for (;;)
+   {
+      if (_rJSON_LIKELY(p != end))
+      {
+         unsigned char c = *p;
+         if (_rJSON_LIKELY(c != '"' && c != '\\' && c >= 0x20))
+         {
+            /* handle most common case first, it's faster */
+            utf8mask |= c;
+            p++;
+         }
+         else if (c == '"')
+         {
+            json->input_p = p + 1;
+            if (json->string_len == 0 && p + 1 != end)
+            {
+               /* raw string fully inside input buffer, pass through */
+               json->string_len          = p - raw;
+               json->string_pass_through = (char*)raw;
+            }
+            else if (raw != p && !_rjson_pushchars(json, raw, p)) /* OOM */
+               return RJSON_ERROR;
+            /* Contains invalid UTF-8 byte sequences */
+            if ((utf8mask & 0x80) && !_rjson_validate_utf8(json))
+               return RJSON_ERROR;
+            return RJSON_STRING;
+         }
+         else if (c == '\\')
+         {
+            _rjson_char_t esc;
+            if (raw != p)
+            {
+               /* Can't pass through string with escapes, use string buffer */
+               if (!_rjson_pushchars(json, raw, p))
+                  return RJSON_ERROR;
+            }
+            json->input_p = p + 1;
+            esc = _rjson_char_get(json);
+            switch (esc)
+            {
+               case 'u':
+                  if (!_rjson_read_unicode(json))
+                     return RJSON_ERROR;
+                  break;
+
+               case 'b':
+                  esc = '\b';
+                  goto escape_pushchar;
+               case 'f':
+                  esc = '\f';
+                  goto escape_pushchar;
+               case 'n':
+                  esc = '\n';
+                  goto escape_pushchar;
+               case 'r': 
+                  if (!(json->option_flags & RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN))
+                  {
+                     esc = '\r';
+                     goto escape_pushchar;
+                  }
+                  break;
+               case 't':
+                  esc = '\t';
+                  goto escape_pushchar;
+               case '/':
+               case '"':
+               case '\\':
+escape_pushchar:
+                  if (!_rjson_pushchar(json, esc))
+                     return RJSON_ERROR;
+                  break;
+
+               case _rJSON_EOF:
+                  return _rjson_error(json, "unterminated string literal in escape");
+
+               default:
+                  return _rjson_error_char(json, "invalid escaped %s", esc);
+            }
+            raw = p = json->input_p;
+            end     = json->input_end;
+         }
+         else if (!(json->option_flags & RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS))
+            return _rjson_error_char(json, "unescaped control character %s in string", c);
+         else
+            p++;
+      }
+      else
+      {
+         if (raw != p)
+         {
+            /* not fully inside input buffer, copy to string buffer */
+            if (!_rjson_pushchars(json, raw, p))
+               return RJSON_ERROR;
+         }
+         if (!_rjson_io_input(json))
+            return _rjson_error(json, "unterminated string literal");
+         raw = p = json->input_p;
+         end     = json->input_end;
+      }
+   }
+}
+
+static enum rjson_type _rjson_read_number(rjson_t *json)
+{
+   const unsigned char *p     = json->input_p - 1;
+   const unsigned char *end   = json->input_end;
+   const unsigned char *start = p;
+
+   json->string_len = 0;
+   json->string_pass_through = NULL;
+   for (;;)
+   {
+      if (_rJSON_LIKELY(p != end))
+      {
+         switch (*p++)
+         {
+            case '+': case '-': case '.':
+            case '0': case '1': case '2': case '3': case '4':
+            case '5': case '6': case '7': case '8': case '9':
+            case 'E': case 'e':
+               continue;
+         }
+         p--;
+         json->input_p = p;
+         if (!_rjson_pushchars(json, start, p))
+            return RJSON_ERROR; /* out of memory */
+         break;
+      }
+      else
+      {
+         /* number sequences are always copied to the string buffer */
+         if (!_rjson_pushchars(json, start, p))
+            return RJSON_ERROR;
+         if (!_rjson_io_input(json))
+         {
+            /* EOF here is not an error for a number */
+            json->input_p = json->input_end;
+            break;
+         }
+         start = p = json->input_p;
+         end = json->input_end;
+      }
+   }
+
+   p = (const unsigned char *)json->string;
+   end = (p + json->string_len);
+
+   /* validate json number */
+   if (*p == '-' && ++p == end)
+      goto invalid_number;
+   if (*p == '0')
+   {
+      if (++p == end)
+         return RJSON_NUMBER;
+   }
+   else
+   {
+      if (*p < '1' || *p > '9')
+         goto invalid_number;
+      do
+      {
+         if (++p == end)
+            return RJSON_NUMBER;
+      }
+      while (*p >= '0' && *p <= '9');
+   }
+   if (*p == '.')
+   {
+      if (++p == end)
+         goto invalid_number;
+      if (*p < '0' || *p > '9')
+         goto invalid_number;
+      do 
+      {
+         if (++p == end)
+            return RJSON_NUMBER;
+      }
+      while (*p >= '0' && *p <= '9');
+   }
+   if (((*p)|0x20) == 'e')
+   {
+      if (++p == end)
+         goto invalid_number;
+      if ((*p == '-' || *p == '+') && ++p == end)
+         goto invalid_number;
+      if (*p < '0' || *p > '9')
+         goto invalid_number;
+      do
+      {
+         if (++p == end)
+            return RJSON_NUMBER;
+      }
+      while (*p >= '0' && *p <= '9');
+   }
+invalid_number:
+   return _rjson_error_char(json, "unexpected %s in number",
+         (p == json->input_end ? _rJSON_EOF : p[p == end ? -1 : 0]));
+}
+
+static enum rjson_type _rjson_push_stack(rjson_t *json, enum _rjson_token t)
+{
+   if (json->stack_top + 1 == json->stack + json->stack_cap)
+   {
+      /* reached allocated stack size, either reallocate or abort */
+      unsigned int new_stack_cap;
+      struct _rjson_stack *new_stack;
+      size_t stack_alloc;
+      if (json->stack_cap == json->stack_max)
+         return _rjson_error(json, "maximum depth of nesting reached");
+
+      new_stack_cap = json->stack_cap + 4;
+      if (new_stack_cap > json->stack_max)
+         new_stack_cap = json->stack_max;
+      stack_alloc = new_stack_cap * sizeof(struct _rjson_stack);
+      if (json->stack != json->inline_stack)
+         new_stack = (struct _rjson_stack *)realloc(json->stack, stack_alloc);
+      else if ((new_stack = (struct _rjson_stack*)malloc(stack_alloc)) != NULL)
+         memcpy(new_stack, json->inline_stack, sizeof(json->inline_stack));
+      if (!new_stack)
+         return _rjson_error(json, "out of memory");
+
+      json->stack     = new_stack;
+      json->stack_top = new_stack + json->stack_cap - 1;
+      json->stack_cap = new_stack_cap;
+   }
+   json->stack_top++;
+   json->stack_top->count = 0;
+   return (json->stack_top->type =
+            (t == _rJSON_TOK_ARRAY ? RJSON_ARRAY : RJSON_OBJECT));
+}
+
+static enum rjson_type _rjson_read_name(rjson_t *json, const char *pattern, enum rjson_type type)
+{
+   _rjson_char_t c;
+   const char *p;
+   for (p = pattern; *p; p++)
+   {
+      if ((_rjson_char_t)*p != (c = _rjson_char_get(json)))
+         return _rjson_error_char(json, "unexpected %s in value", c);
+   }
+   return type;
+}
+
+static bool _rjson_optional_skip(rjson_t *json, const unsigned char **p, const unsigned char **end)
+{
+   unsigned char c, skip = (*p)[-1];
+   int state = 0;
+
+   if (skip == '/' && !(json->option_flags & RJSON_OPTION_ALLOW_COMMENTS))
+      return false;
+
+   if (     skip == 0xEF && (!(json->option_flags & RJSON_OPTION_ALLOW_UTF8BOM)
+         || json->source_line != 1 || json->source_column_p != json->input_p))
+      return false;
+
+   for (;;)
+   {
+      if (*p == *end)
+      {
+         if (!_rjson_io_input(json))
+         {
+            _rjson_error(json, "unfinished %s",
+                  (skip == '/' ? "comment" : "utf8 byte order mark"));
+            break;
+         }
+         *p   = json->input_p;
+         *end = json->input_end;
+      }
+      c = *(*p)++;
+      if (skip == '/')
+      {
+         if      (state == 0 && c == '/')
+            state = 1;
+         else if (state == 0 && c == '*')
+            state = 2;
+         else if (state == 0)
+            break;
+         else if (state == 1 && c == '\n')
+            return true;
+         else if (state == 2 && c == '*')
+            state = 3;
+         else if (state == 3 && c == '/')
+            return true;
+         else if (state == 3 && c != '*')
+            state = 2;
+      }
+      else if (skip == 0xEF)
+      {
+         /* Silence warning - state being set never used */
+         if      (state == 0 && c == 0xBB)
+            state = 1;
+         else if (state == 1 && c == 0xBF)
+            return true;
+         else
+            break;
+      }
+   }
+   return false;
+}
+
+enum rjson_type rjson_next(rjson_t *json)
+{
+   unsigned char tok;
+   struct _rjson_stack *stack = json->stack_top;
+   const unsigned char *p     = json->input_p;
+   const unsigned char *end   = json->input_end;
+   unsigned char passed_token = false;
+
+   /* JSON token look-up-table */
+   static const unsigned char token_lut[256] =
+   {
+      #define i _rJSON_TOK_ERROR
+      /*   0 | 0x00 |   */ i,i,i,i,i,i,i,i,i,
+      /*   9 | 0x09 |\t */ _rJSON_TOK_WHITESPACE,
+      /*  10 | 0x0A |\n */ _rJSON_TOK_NEWLINE, i,i,
+      /*  13 | 0x0D |\r */ _rJSON_TOK_WHITESPACE, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
+      /*  32 | 0x20 |   */ _rJSON_TOK_WHITESPACE, i,
+      /*  34 | 0x22 | " */ _rJSON_TOK_STRING, i,i,i,i,i,i,i,i,i,
+      /*  44 | 0x2C | , */ _rJSON_TOK_COMMA,
+      /*  45 | 0x2D | - */ _rJSON_TOK_NUMBER, i,
+      /*  47 | 0x2F | / */ _rJSON_TOK_OPTIONAL_SKIP,
+      /*  48 | 0x30 | 0 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,
+      /*  53 | 0x35 | 5 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,
+      /*  58 | 0x3A | : */ _rJSON_TOK_COLON, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
+      /*  91 | 0x5B | [ */ _rJSON_TOK_ARRAY, i,
+      /*  93 | 0x5D | ] */ _rJSON_TOK_ARRAY_END, i,i,i,i,i,i,i,i,
+      /* 102 | 0x66 | f */ _rJSON_TOK_FALSE, i,i,i,i,i,i,i,
+      /* 110 | 0x6E | n */ _rJSON_TOK_NULL, i,i,i,i,i,
+      /* 116 | 0x74 | t */ _rJSON_TOK_TRUE, i,i,i,i,i,i,
+      /* 123 | 0x7B | { */ _rJSON_TOK_OBJECT, i,
+      /* 125 | 0x7D | } */ _rJSON_TOK_OBJECT_END,
+      /* 126 | 0x7E | ~ */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
+      /* 164 | 0xA4 |   */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
+      /* 202 | 0xCA |   */ i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
+      /* 239 | 0xEF |   */ _rJSON_TOK_OPTIONAL_SKIP, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i
+      #undef i
+   };
+
+   if (_rJSON_LIKELY(stack->type != RJSON_ERROR))
+   {
+      for (;;)
+      {
+         if (_rJSON_LIKELY(p != end))
+         {
+            tok = token_lut[*p++];
+            if (_rJSON_LIKELY(tok > _rJSON_TOK_OPTIONAL_SKIP))
+            {
+               /* Actual JSON token, process below */
+            }
+            else if (_rJSON_LIKELY(tok == _rJSON_TOK_WHITESPACE))
+               continue;
+            else if (tok == _rJSON_TOK_NEWLINE)
+            {
+               json->source_line++;
+               json->source_column_p = p;
+               continue;
+            }
+            else if (tok == _rJSON_TOK_OPTIONAL_SKIP)
+            {
+               if (_rjson_optional_skip(json, &p, &end))
+                  continue;
+            }
+         }
+         else if (_rJSON_LIKELY(_rjson_io_input(json)))
+         {
+            p   = json->input_p;
+            end = json->input_end;
+            continue;
+         }
+         else
+         {
+            p   = json->input_end;
+            tok = _rJSON_TOK_EOF;
+         }
+
+         if (stack->type == RJSON_OBJECT)
+         {
+            if (stack->count & 1)
+            {
+               /* Expecting colon followed by value. */
+               if (passed_token)
+                  goto read_value;
+               if (_rJSON_LIKELY(tok == _rJSON_TOK_COLON))
+               {
+                  passed_token = true;
+                  continue;
+               }
+               json->input_p = p;
+               return _rjson_error_token(json,
+                     "expected ':' not %s after member name", (enum _rjson_token)tok);
+            }
+            if (passed_token)
+            {
+               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))
+                  goto read_value;
+               json->input_p = p;
+               return _rjson_error(json, "expected member name after ','");
+            }
+            if (tok == _rJSON_TOK_OBJECT_END)
+            {
+               json->input_p = p;
+               json->stack_top--;
+               return RJSON_OBJECT_END;
+            }
+            if (stack->count == 0)
+            {
+               /* No member name/value pairs yet. */
+               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))
+                  goto read_value;
+               json->input_p = p;
+               return _rjson_error(json, "expected member name or '}'");
+            }
+            /* Expecting comma followed by member name. */
+            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))
+            {
+               passed_token = true;
+               continue;
+            }
+            json->input_p = p;
+            return _rjson_error_token(json,
+                  "expected ',' or '}' not %s after member value", (enum _rjson_token)tok);
+         }
+         else if (stack->type == RJSON_ARRAY)
+         {
+            if (passed_token)
+               goto read_value;
+            if (tok == _rJSON_TOK_ARRAY_END)
+            {
+               json->input_p = p;
+               json->stack_top--;
+               return RJSON_ARRAY_END;
+            }
+            if (stack->count == 0)
+               goto read_value;
+            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))
+            {
+               passed_token = true;
+               continue;
+            }
+            json->input_p = p;
+            return _rjson_error_token(json,
+                  "expected ',' or ']' not %s in array", (enum _rjson_token)tok);
+         }
+         else
+         {
+            if (_rJSON_LIKELY(!stack->count && tok != _rJSON_TOK_EOF))
+               goto read_value;
+            json->input_p = p;
+            if (!stack->count)
+               return _rjson_error(json, "reached end without any data");
+            if (tok == _rJSON_TOK_EOF)
+               return RJSON_DONE;
+            if (!(json->option_flags & RJSON_OPTION_ALLOW_TRAILING_DATA))
+               return _rjson_error_token(json,
+                     "expected end of stream instead of %s", (enum _rjson_token)tok);
+            json->input_p--;
+            return RJSON_DONE;
+         }
+
+         /* read value for current token */
+         read_value:
+         json->input_p = p;
+         stack->count++;
+         /* This is optimal when there are many strings, otherwise a switch statement
+          * or a function pointer table is better (depending on compiler/cpu) */
+         if      (tok == _rJSON_TOK_STRING)
+            return _rjson_read_string(json);
+         else if (tok == _rJSON_TOK_NUMBER)
+            return _rjson_read_number(json);
+         else if (tok == _rJSON_TOK_OBJECT)
+            return _rjson_push_stack(json, _rJSON_TOK_OBJECT);
+         else if (tok == _rJSON_TOK_ARRAY)
+            return _rjson_push_stack(json, _rJSON_TOK_ARRAY);
+         else if (tok == _rJSON_TOK_TRUE)
+            return _rjson_read_name(json, "rue", RJSON_TRUE);
+         else if (tok == _rJSON_TOK_FALSE)
+            return _rjson_read_name(json, "alse", RJSON_FALSE);
+         else if (tok == _rJSON_TOK_NULL)
+            return _rjson_read_name(json, "ull", RJSON_NULL);
+         else return _rjson_error_token(json,
+               "unexpected %s in value", (enum _rjson_token)tok);
+      }
+   }
+   return RJSON_ERROR;
+}
+
+void _rjson_setup(rjson_t *json, rjson_io_t io, void *user_data, int input_len)
+{
+   json->io                  = io;
+   json->user_data           = user_data;
+   json->input_len           = input_len;
+   json->input_p             = json->input_end = json->input_buf + input_len;
+
+   json->stack               = json->inline_stack;
+   json->stack_top           = json->stack;
+   json->stack_top->type     = RJSON_DONE;
+   json->stack_top->count    = 0;
+   json->stack_cap           = (unsigned int)(sizeof(json->inline_stack) / sizeof(json->inline_stack[0]));
+   json->stack_max           = (unsigned int)50;
+
+   json->string              = json->inline_string;
+   json->string_pass_through = NULL;
+   json->string_len          = 0;
+   json->string_cap          = sizeof(json->inline_string);
+
+   json->source_line         = 1;
+   json->source_column_p     = json->input_p;
+   json->option_flags        = 0;
+   json->decimal_sep         = 0;
+}
+
+rjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size)
+{
+   rjson_t* json = (rjson_t*)malloc(
+         sizeof(rjson_t) - sizeof(((rjson_t*)0)->input_buf) + io_block_size);
+   if (json) _rjson_setup(json, io, user_data, io_block_size);
+   return json;
+}
+
+static int _rjson_buffer_io(void* buf, int len, void *user)
+{
+   const char **ud = (const char **)user;
+   if (ud[1] - ud[0] < len) len = (int)(ud[1] - ud[0]);
+   memcpy(buf, ud[0], len);
+   ud[0] += len;
+   return len;
+}
+
+rjson_t *rjson_open_buffer(const void *buffer, size_t size)
+{
+   rjson_t *json   = (rjson_t *)malloc(sizeof(rjson_t) + sizeof(const char *)*2);
+   const char **ud = (const char **)(json + 1);
+   if (!json)
+      return NULL;
+   ud[0] = (const char *)buffer;
+   ud[1] = ud[0] + size;
+   _rjson_setup(json, _rjson_buffer_io, (void*)ud, sizeof(json->input_buf));
+   return json;
+}
+
+rjson_t *rjson_open_string(const char *string, size_t len)
+{
+   return rjson_open_buffer(string, len);
+}
+
+static int _rjson_stream_io(void* buf, int len, void *user)
+{
+   return (int)intfstream_read((intfstream_t*)user, buf, (uint64_t)len);
+}
+
+rjson_t *rjson_open_stream(struct intfstream_internal *stream)
+{
+   /* Allocate an input buffer based on the file size */
+   int64_t size = intfstream_get_size(stream);
+   int io_size  =
+         (size > 1024*1024 ? 4096 :
+         (size >  256*1024 ? 2048 : 1024));
+   return rjson_open_user(_rjson_stream_io, stream, io_size);
+}
+
+static int _rjson_rfile_io(void* buf, int len, void *user)
+{
+   return (int)filestream_read((RFILE*)user, buf, (int64_t)len);
+}
+
+rjson_t *rjson_open_rfile(RFILE *rfile)
+{
+   /* Allocate an input buffer based on the file size */
+   int64_t size = filestream_get_size(rfile);
+   int io_size =
+         (size > 1024*1024 ? 4096 :
+         (size >  256*1024 ? 2048 : 1024));
+   return rjson_open_user(_rjson_rfile_io, rfile, io_size);
+}
+
+void rjson_set_options(rjson_t *json, char rjson_option_flags)
+{
+   json->option_flags = rjson_option_flags;
+}
+
+void rjson_set_max_depth(rjson_t *json, unsigned int max_depth)
+{
+   json->stack_max = max_depth;
+}
+
+const char *rjson_get_string(rjson_t *json, size_t *length)
+{
+   char* str             = (json->string_pass_through 
+         ? json->string_pass_through : json->string);
+   if (length)
+      *length            = json->string_len;
+   str[json->string_len] = '\0';
+   return str;
+}
+
+double rjson_get_double(rjson_t *json)
+{
+   char* str = (json->string_pass_through ? json->string_pass_through : json->string);
+   str[json->string_len] = '\0';
+   if (json->decimal_sep != '.')
+   {
+      /* handle locale that uses a non-standard decimal separator */
+      char *p;
+      if (json->decimal_sep == 0)
+      {
+         char test[4];
+         snprintf(test, sizeof(test), "%.1f", 0.0f);
+         json->decimal_sep = test[1];
+      }
+      if (json->decimal_sep != '.' && (p = strchr(str, '.')) != NULL)
+      {
+         double res;
+         *p  = json->decimal_sep;
+         res = atof(str);
+         *p  = '.';
+         return res;
+      }
+   }
+   return atof(str);
+}
+
+int rjson_get_int(rjson_t *json)
+{
+   char* str = (json->string_pass_through ? json->string_pass_through : json->string);
+   str[json->string_len] = '\0';
+   return atoi(str);
+}
+
+const char *rjson_get_error(rjson_t *json)
+{
+   return (json->stack_top->type == RJSON_ERROR ? json->error_text : "");
+}
+
+void rjson_set_error(rjson_t *json, const char* error)
+{
+   _rjson_error(json, "%s", error);
+}
+
+size_t rjson_get_source_line(rjson_t *json)
+{
+   return json->source_line;
+}
+
+size_t rjson_get_source_column(rjson_t *json)
+{
+   return (json->input_p == json->source_column_p ? 1 :
+         json->input_p - json->source_column_p);
+}
+
+int rjson_get_source_context_len(rjson_t *json)
+{
+   const unsigned char *from = json->input_buf, *to = json->input_end, *p = json->input_p;
+   return (int)(((p + 256 < to ? p + 256 : to) - (p > from + 256 ? p - 256 : from)));
+}
+
+const char* rjson_get_source_context_buf(rjson_t *json)
+{
+   /* inside the input buffer, some " may have been replaced with \0. */
+   const unsigned char *p = json->input_p, *from = json->input_buf;
+   unsigned char *i = json->input_buf;
+   for (; i != json->input_end; i++)
+   {
+      if (*i == '\0')
+         *i = '"';
+   }
+   return (const char*)(p > from + 256 ? p - 256 : from);
+}
+
+bool rjson_check_context(rjson_t *json, unsigned int depth, ...)
+{
+   va_list ap;
+   const struct _rjson_stack *stack = json->stack, *stack_top = json->stack_top;
+   if ((unsigned int)(stack_top - stack) != depth)
+      return false;
+   va_start(ap, depth);
+   while (++stack <= stack_top)
+   {
+      if (va_arg(ap, int) == (int)stack->type) continue;
+      va_end(ap);
+      return false;
+   }
+   va_end(ap);
+   return true;
+}
+
+unsigned int rjson_get_context_depth(rjson_t *json)
+{
+   return (unsigned int)(json->stack_top - json->stack);
+}
+
+size_t rjson_get_context_count(rjson_t *json)
+{
+   return json->stack_top->count;
+}
+
+enum rjson_type rjson_get_context_type(rjson_t *json)
+{
+   return json->stack_top->type;
+}
+
+void rjson_free(rjson_t *json)
+{
+   if (json->stack != json->inline_stack)
+      free(json->stack);
+   if (json->string != json->inline_string)
+      free(json->string);
+   free(json);
+}
+
+static bool _rjson_nop_default(void *context) { return true; }
+static bool _rjson_nop_string(void *context, const char *value, size_t length) { return true; }
+static bool _rjson_nop_bool(void *context, bool value) { return true; }
+
+enum rjson_type rjson_parse(rjson_t *json, void* context,
+      bool (*object_member_handler)(void *context, const char *str, size_t len),
+      bool (*string_handler       )(void *context, const char *str, size_t len),
+      bool (*number_handler       )(void *context, const char *str, size_t len),
+      bool (*start_object_handler )(void *context),
+      bool (*end_object_handler   )(void *context),
+      bool (*start_array_handler  )(void *context),
+      bool (*end_array_handler    )(void *context),
+      bool (*boolean_handler      )(void *context, bool value),
+      bool (*null_handler         )(void *context))
+{
+   bool in_object = false;
+   size_t len;
+   const char* string;
+   if (!object_member_handler) object_member_handler = _rjson_nop_string;
+   if (!string_handler       ) string_handler        = _rjson_nop_string;
+   if (!number_handler       ) number_handler        = _rjson_nop_string;
+   if (!start_object_handler ) start_object_handler  = _rjson_nop_default;
+   if (!end_object_handler   ) end_object_handler    = _rjson_nop_default;
+   if (!start_array_handler  ) start_array_handler   = _rjson_nop_default;
+   if (!end_array_handler    ) end_array_handler     = _rjson_nop_default;
+   if (!boolean_handler      ) boolean_handler       = _rjson_nop_bool;
+   if (!null_handler         ) null_handler          = _rjson_nop_default;
+   for (;;)
+   {
+      switch (rjson_next(json))
+      {
+         case RJSON_STRING:
+            string = rjson_get_string(json, &len);
+            if (_rJSON_LIKELY(
+                  (in_object && (json->stack_top->count & 1) ?
+                     object_member_handler : string_handler)
+                     (context, string, len)))
+               continue;
+            return RJSON_STRING;
+         case RJSON_NUMBER:
+            string = rjson_get_string(json, &len);
+            if (_rJSON_LIKELY(number_handler(context, string, len)))
+               continue;
+            return RJSON_NUMBER;
+         case RJSON_OBJECT:
+            in_object = true;
+            if (_rJSON_LIKELY(start_object_handler(context)))
+               continue;
+            return RJSON_OBJECT;
+         case RJSON_ARRAY:
+            in_object = false;
+            if (_rJSON_LIKELY(start_array_handler(context)))
+               continue;
+            return RJSON_ARRAY;
+         case RJSON_OBJECT_END:
+            if (_rJSON_LIKELY(end_object_handler(context)))
+            {
+               in_object = (json->stack_top->type == RJSON_OBJECT);
+               continue;
+            }
+            return RJSON_OBJECT_END;
+         case RJSON_ARRAY_END:
+            if (_rJSON_LIKELY(end_array_handler(context)))
+            {
+               in_object = (json->stack_top->type == RJSON_OBJECT);
+               continue;
+            }
+            return RJSON_ARRAY_END;
+         case RJSON_TRUE:
+            if (_rJSON_LIKELY(boolean_handler(context, true)))
+               continue;
+            return RJSON_TRUE;
+         case RJSON_FALSE:
+            if (_rJSON_LIKELY(boolean_handler(context, false)))
+               continue;
+            return RJSON_FALSE;
+         case RJSON_NULL:
+            if (_rJSON_LIKELY(null_handler(context)))
+               continue;
+            return RJSON_NULL;
+         case RJSON_ERROR:
+            return RJSON_ERROR;
+         case RJSON_DONE:
+            return RJSON_DONE;
+      }
+   }
+}
+
+bool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,
+      bool (*object_member_handler)(void *context, const char *str, size_t len),
+      bool (*string_handler       )(void *context, const char *str, size_t len),
+      bool (*number_handler       )(void *context, const char *str, size_t len),
+      bool (*start_object_handler )(void *context),
+      bool (*end_object_handler   )(void *context),
+      bool (*start_array_handler  )(void *context),
+      bool (*end_array_handler    )(void *context),
+      bool (*boolean_handler      )(void *context, bool value),
+      bool (*null_handler         )(void *context),
+      void (*error_handler        )(void *context, int line, int col, const char* error))
+{
+   const char *user_data[2];
+   rjson_t json;
+   user_data[0] = string;
+   user_data[1] = string + len;
+   _rjson_setup(&json, _rjson_buffer_io, (void*)user_data, sizeof(json.input_buf));
+   rjson_set_options(&json, option_flags);
+   if (rjson_parse(&json, context,
+         object_member_handler, string_handler, number_handler,
+         start_object_handler, end_object_handler,
+         start_array_handler, end_array_handler,
+         boolean_handler, null_handler) == RJSON_DONE)
+      return true;
+   if (error_handler)
+      error_handler(context,
+            (int)rjson_get_source_line(&json),
+            (int)rjson_get_source_column(&json),
+            rjson_get_error(&json));
+   return false;
+}
+
+struct rjsonwriter
+{
+   char* buf;
+   int buf_num, buf_cap;
+
+   rjsonwriter_io_t io;
+   void *user_data;
+
+   const char* error_text;
+   char option_flags, decimal_sep;
+   bool buf_is_output, final_flush;
+
+   char inline_buf[1024];
+};
+
+rjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data)
+{
+   rjsonwriter_t* writer = (rjsonwriter_t*)malloc(sizeof(rjsonwriter_t));
+   if (!writer)
+      return NULL;
+
+   writer->buf           = writer->inline_buf;
+   writer->buf_num       = 0;
+   writer->buf_cap       = sizeof(writer->inline_buf);
+
+   writer->error_text    = NULL;
+   writer->option_flags  = writer->decimal_sep = 0;
+   writer->buf_is_output = writer->final_flush = false;
+
+   writer->io            = io;
+   writer->user_data     = user_data;
+
+   return writer;
+}
+
+static int _rjsonwriter_stream_io(const void* buf, int len, void *user)
+{
+   return (int)intfstream_write((intfstream_t*)user, buf, (uint64_t)len);
+}
+
+rjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream)
+{
+   return rjsonwriter_open_user(_rjsonwriter_stream_io, stream);
+}
+
+static int _rjsonwriter_rfile_io(const void* buf, int len, void *user)
+{
+   return (int)filestream_write((RFILE*)user, buf, (int64_t)len);
+}
+
+rjsonwriter_t *rjsonwriter_open_rfile(RFILE *rfile)
+{
+   return rjsonwriter_open_user(_rjsonwriter_rfile_io, rfile);
+}
+
+static int _rjsonwriter_memory_io(const void* buf, int len, void *user)
+{
+   rjsonwriter_t *writer = (rjsonwriter_t *)user;
+   bool is_append        = (buf != writer->buf);
+   int new_cap           = writer->buf_num + (is_append ? len : 0) + 512;
+   if (!writer->final_flush && (is_append || new_cap > writer->buf_cap))
+   {
+      bool can_realloc   = (writer->buf != writer->inline_buf);
+      char* new_buf      = (char*)(can_realloc ? realloc(writer->buf, new_cap) : malloc(new_cap));
+      if (!new_buf)
+         return 0;
+      if (!can_realloc)
+         memcpy(new_buf, writer->buf, writer->buf_num);
+      if (is_append)
+      {
+         memcpy(new_buf + writer->buf_num, buf, len);
+         writer->buf_num += len;
+      }
+      writer->buf        = new_buf;
+      writer->buf_cap    = new_cap;
+   }
+   return len;
+}
+
+rjsonwriter_t *rjsonwriter_open_memory(void)
+{
+   rjsonwriter_t *writer = rjsonwriter_open_user(_rjsonwriter_memory_io, NULL);
+   if (!writer)
+      return NULL;
+   writer->user_data     = writer;
+   writer->buf_is_output = true;
+   return writer;
+}
+
+char* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len)
+{
+   if (writer->io != _rjsonwriter_memory_io || writer->error_text)
+      return NULL;
+   if (writer->buf_num == writer->buf_cap)
+      rjsonwriter_flush(writer);
+   writer->buf[writer->buf_num] = '\0';
+   if (len)
+      *len = writer->buf_num;
+   return writer->buf;
+}
+
+int rjsonwriter_count_memory_buffer(rjsonwriter_t *writer)
+{
+   return writer->buf_num;
+}
+
+void rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len)
+{
+   if (keep_len <= writer->buf_num)
+      writer->buf_num = (keep_len < 0 ? 0 : keep_len);
+}
+
+bool rjsonwriter_free(rjsonwriter_t *writer)
+{
+   bool res;
+   writer->final_flush = true;
+   res = rjsonwriter_flush(writer);
+   if (writer->buf != writer->inline_buf)
+      free(writer->buf);
+   free(writer);
+   return res;
+}
+
+void rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags)
+{
+   writer->option_flags = rjsonwriter_option_flags;
+}
+
+bool rjsonwriter_flush(rjsonwriter_t *writer)
+{
+   if (writer->buf_num && !writer->error_text && writer->io(writer->buf,
+            writer->buf_num, writer->user_data) != writer->buf_num)
+      writer->error_text = "output error";
+   if (!writer->buf_is_output || writer->error_text)
+      writer->buf_num = 0;
+   return !writer->error_text;
+}
+
+const char *rjsonwriter_get_error(rjsonwriter_t *writer)
+{
+   return (writer->error_text ? writer->error_text : "");
+}
+
+void rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len)
+{
+   if (writer->buf_num + len > writer->buf_cap)
+      rjsonwriter_flush(writer);
+   if (len == 1)
+   {
+      if (buf[0] > ' ' ||
+            !(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))
+         writer->buf[writer->buf_num++] = buf[0];
+   }
+   else
+   {
+      int add = writer->buf_cap - writer->buf_num;
+      if (add > len)
+         add = len;
+      memcpy(writer->buf + writer->buf_num, buf, add);
+      writer->buf_num += add;
+      if (len == add)
+         return;
+      rjsonwriter_flush(writer);
+      len -= add;
+      buf += add;
+      if (writer->buf_num + len <= writer->buf_cap)
+      {
+         memcpy(writer->buf + writer->buf_num, buf, len);
+         writer->buf_num += len;
+      }
+      else if (writer->io(buf, len, writer->user_data) != len)
+         writer->error_text = "output error";
+   }
+}
+
+void rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...)
+{
+   int available, need;
+   va_list ap, ap2;
+   if (writer->buf_num >= writer->buf_cap - 16)
+      rjsonwriter_flush(writer);
+   available = (writer->buf_cap - writer->buf_num);
+   va_start(ap, fmt);
+   need = vsnprintf(writer->buf + writer->buf_num, available, fmt, ap);
+   va_end(ap);
+   if (need <= 0)
+      return;
+   if (need < available)
+   {
+      writer->buf_num += need;
+      return;
+   }
+   rjsonwriter_flush(writer);
+   if (writer->buf_num + need >= writer->buf_cap)
+   {
+      int newcap   = writer->buf_num + need + 1;
+      char* newbuf = (char*)malloc(newcap);
+      if (!newbuf)
+      {
+         if (!writer->error_text)
+            writer->error_text = "out of memory";
+         return;
+      }
+      if (writer->buf_num)
+         memcpy(newbuf, writer->buf, writer->buf_num);
+      if (writer->buf != writer->inline_buf)
+         free(writer->buf);
+      writer->buf = newbuf;
+      writer->buf_cap = newcap;
+   }
+   va_start(ap2, fmt);
+   vsnprintf(writer->buf + writer->buf_num, writer->buf_cap - writer->buf_num, fmt, ap2);
+   va_end(ap2);
+   writer->buf_num += need;
+}
+
+void _rjsonwriter_add_escaped(rjsonwriter_t *writer, unsigned char c)
+{
+   char esc_buf[8], esc_len = 2;
+   const char* esc;
+   switch (c)
+   {
+      case '\b':
+         esc = "\\b";
+         break;
+      case '\t':
+         esc = "\\t";
+         break;
+      case '\n':
+         esc = "\\n";
+         break;
+      case '\f':
+         esc = "\\f";
+         break;
+      case '\r':
+         esc = "\\r";
+         break;
+      case '\"':
+         esc = "\\\"";
+         break;
+      case '\\':
+         esc = "\\\\";
+         break;
+      case '/':
+         esc = "\\/";
+         break;
+      default:
+         snprintf(esc_buf, sizeof(esc_buf), "\\u%04x", c);
+         esc     = esc_buf;
+         esc_len = 6;
+   }
+   rjsonwriter_raw(writer, esc, esc_len);
+}
+
+void rjsonwriter_add_string(rjsonwriter_t *writer, const char *value)
+{
+   const char *p = (const char*)value, *raw = p;
+   unsigned char c;
+   rjsonwriter_raw(writer, "\"", 1);
+   if (!p)
+      goto string_end;
+   while ((c = (unsigned char)*p++) != '\0')
+   {
+      /* forward slash is special, it should be escaped if the previous character
+       * was a < (intended to avoid having </script> html tags in JSON files) */
+      if (   c >= 0x20 && c != '\"' && c != '\\' &&
+            (c != '/' || p < value + 2 || p[-2] != '<'))
+         continue;
+      if (raw != p - 1)
+         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
+      _rjsonwriter_add_escaped(writer, c);
+      raw = p;
+   }
+   if (raw != p - 1)
+      rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
+string_end:
+   rjsonwriter_raw(writer, "\"", 1);
+}
+
+void rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len)
+{
+   const char *p = (const char*)value, *raw = p, *end = p + len;
+   rjsonwriter_raw(writer, "\"", 1);
+   while (p != end)
+   {
+      unsigned char c = (unsigned char)*p++;
+      if (      c >= 0x20 && c != '\"' && c != '\\'
+            && (c != '/' || p < value + 2 || p[-2] != '<'))
+         continue;
+      if (raw != p - 1)
+         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));
+      _rjsonwriter_add_escaped(writer, c);
+      raw = p;
+   }
+   if (raw != end)
+      rjsonwriter_raw(writer, raw, (int)(end - raw));
+   rjsonwriter_raw(writer, "\"", 1);
+}
+
+void rjsonwriter_add_double(rjsonwriter_t *writer, double value)
+{
+   int old_buf_num = writer->buf_num;
+   rjsonwriter_rawf(writer, "%G", value);
+   if (writer->decimal_sep != '.')
+   {
+      /* handle locale that uses a non-standard decimal separator */
+      char *p, *str;
+      if (writer->decimal_sep == 0)
+      {
+         char test[4];
+         snprintf(test, sizeof(test), "%.1f", 0.0f);
+         if ((writer->decimal_sep = test[1]) == '.')
+            return;
+      }
+      str = writer->buf + (old_buf_num > writer->buf_num ? 0 : old_buf_num);
+      if ((p = strchr(str, writer->decimal_sep)) != NULL)
+         *p = '.';
+   }
+}
+
+void rjsonwriter_add_spaces(rjsonwriter_t *writer, int count)
+{
+   if (!(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))
+      for (; count > 0; count -= 8)
+         rjsonwriter_raw(writer, "        ", (count > 8 ? 8 : count));
+}
+
+void rjsonwriter_add_tabs(rjsonwriter_t *writer, int count)
+{
+   if (!(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))
+      for (; count > 0; count -= 8)
+         rjsonwriter_raw(writer, "\t\t\t\t\t\t\t\t", (count > 8 ? 8 : count));
+}
+
+#undef _rJSON_EOF
+#undef _rJSON_LIKELY
diff --git a/deps/libretro-common/formats/libchdr/libchdr_bitstream.c b/deps/libretro-common/formats/libchdr/libchdr_bitstream.c
new file mode 100644 (file)
index 0000000..1a6cf73
--- /dev/null
@@ -0,0 +1,119 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    bitstream.c
+
+    Helper classes for reading/writing at the bit level.
+
+***************************************************************************/
+
+#include <stdlib.h>
+#include <libchdr/bitstream.h>
+
+/***************************************************************************
+ *  INLINE FUNCTIONS
+ ***************************************************************************
+ */
+
+int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); }
+
+/*-------------------------------------------------
+ *  create_bitstream - constructor
+ *-------------------------------------------------
+ */
+
+struct bitstream* create_bitstream(const void *src, uint32_t srclength)
+{
+       struct bitstream* bitstream = (struct bitstream*)malloc(sizeof(struct bitstream));
+       bitstream->buffer = 0;
+       bitstream->bits = 0;
+       bitstream->read = (const uint8_t*)src;
+       bitstream->doffset = 0;
+       bitstream->dlength = srclength;
+       return bitstream;
+}
+
+/*-----------------------------------------------------
+ *  bitstream_peek - fetch the requested number of bits
+ *  but don't advance the input pointer
+ *-----------------------------------------------------
+ */
+
+uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
+{
+       if (numbits == 0)
+               return 0;
+
+       /* fetch data if we need more */
+       if (numbits > bitstream->bits)
+       {
+               while (bitstream->bits <= 24)
+               {
+                       if (bitstream->doffset < bitstream->dlength)
+                               bitstream->buffer |= bitstream->read[bitstream->doffset] << (24 - bitstream->bits);
+                       bitstream->doffset++;
+                       bitstream->bits += 8;
+               }
+       }
+
+       /* return the data */
+       return bitstream->buffer >> (32 - numbits);
+}
+
+/*-----------------------------------------------------
+ *  bitstream_remove - advance the input pointer by the
+ *  specified number of bits
+ *-----------------------------------------------------
+ */
+
+void bitstream_remove(struct bitstream* bitstream, int numbits)
+{
+       bitstream->buffer <<= numbits;
+       bitstream->bits -= numbits;
+}
+
+/*-----------------------------------------------------
+ *  bitstream_read - fetch the requested number of bits
+ *-----------------------------------------------------
+ */
+
+uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
+{
+       uint32_t result = bitstream_peek(bitstream, numbits);
+       bitstream_remove(bitstream, numbits);
+       return result;
+}
+
+/*-------------------------------------------------
+ *  read_offset - return the current read offset
+ *-------------------------------------------------
+ */
+
+uint32_t bitstream_read_offset(struct bitstream* bitstream)
+{
+       uint32_t result = bitstream->doffset;
+       int bits = bitstream->bits;
+       while (bits >= 8)
+       {
+               result--;
+               bits -= 8;
+       }
+       return result;
+}
+
+/*-------------------------------------------------
+ *  flush - flush to the nearest byte
+ *-------------------------------------------------
+ */
+
+uint32_t bitstream_flush(struct bitstream* bitstream)
+{
+       while (bitstream->bits >= 8)
+       {
+               bitstream->doffset--;
+               bitstream->bits -= 8;
+       }
+       bitstream->bits = bitstream->buffer = 0;
+       return bitstream->doffset;
+}
diff --git a/deps/libretro-common/formats/libchdr/libchdr_cdrom.c b/deps/libretro-common/formats/libchdr/libchdr_cdrom.c
new file mode 100644 (file)
index 0000000..f6876e0
--- /dev/null
@@ -0,0 +1,417 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    cdrom.c
+
+    Generic MAME CD-ROM utilties - build IDE and SCSI CD-ROMs on top of this
+
+****************************************************************************
+
+    IMPORTANT:
+    "physical" block addresses are the actual addresses on the emulated CD.
+    "chd" block addresses are the block addresses in the CHD file.
+    Because we pad each track to a 4-frame boundary, these addressing
+    schemes will differ after track 1!
+
+***************************************************************************/
+#ifdef WANT_RAW_DATA_SECTOR
+
+#include <assert.h>
+#include <string.h>
+
+#include <retro_inline.h>
+
+#include <libchdr/cdrom.h>
+
+/***************************************************************************
+    DEBUGGING
+***************************************************************************/
+
+/** @brief  The verbose. */
+#define VERBOSE (0)
+#if VERBOSE
+
+/**
+ * @def LOG(x) do
+ *
+ * @brief   A macro that defines log.
+ *
+ * @param   x   The void to process.
+ */
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+/**
+ * @fn  void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
+ *
+ * @brief   Logerrors the given text.
+ *
+ * @param   text    The text.
+ *
+ * @return  A CLIB_DECL.
+ */
+
+void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
+#else
+
+/**
+ * @def LOG(x);
+ *
+ * @brief   A macro that defines log.
+ *
+ * @param   x   The void to process.
+ */
+
+#define LOG(x)
+#endif
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/** @brief  offset within sector. */
+#define SYNC_OFFSET 0x000
+/** @brief  12 bytes. */
+#define SYNC_NUM_BYTES 12
+
+/** @brief  offset within sector. */
+#define MODE_OFFSET 0x00f
+
+/** @brief  offset within sector. */
+#define ECC_P_OFFSET 0x81c
+/** @brief  2 lots of 86. */
+#define ECC_P_NUM_BYTES 86
+/** @brief  24 bytes each. */
+#define ECC_P_COMP 24
+
+/** @brief  The ECC q offset. */
+#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES)
+/** @brief  2 lots of 52. */
+#define ECC_Q_NUM_BYTES 52
+/** @brief  43 bytes each. */
+#define ECC_Q_COMP 43
+
+/**
+ * @brief   -------------------------------------------------
+ *            ECC lookup tables pre-calculated tables for ECC data calcs
+ *          -------------------------------------------------.
+ */
+
+static const uint8_t ecclow[256] =
+{
+       0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+       0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
+       0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
+       0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
+       0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
+       0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
+       0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+       0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
+       0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03,
+       0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23,
+       0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43,
+       0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63,
+       0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83,
+       0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3,
+       0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3,
+       0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3
+};
+
+/** @brief  The ecchigh[ 256]. */
+static const uint8_t ecchigh[256] =
+{
+       0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05,
+       0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe,
+       0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee,
+       0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15,
+       0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce,
+       0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35,
+       0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25,
+       0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde,
+       0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e,
+       0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75,
+       0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65,
+       0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e,
+       0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45,
+       0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe,
+       0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae,
+       0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55
+};
+
+/**
+ * @brief   -------------------------------------------------
+ *            poffsets - each row represents the addresses used to calculate a byte of the ECC P
+ *            data 86 (*2) ECC P bytes, 24 values represented by each
+ *          -------------------------------------------------.
+ */
+
+static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] =
+{
+       { 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba },
+       { 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb },
+       { 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc },
+       { 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd },
+       { 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be },
+       { 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf },
+       { 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 },
+       { 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 },
+       { 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 },
+       { 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 },
+       { 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 },
+       { 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 },
+       { 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 },
+       { 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 },
+       { 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 },
+       { 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 },
+       { 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca },
+       { 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb },
+       { 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc },
+       { 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd },
+       { 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce },
+       { 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf },
+       { 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 },
+       { 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 },
+       { 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 },
+       { 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 },
+       { 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 },
+       { 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 },
+       { 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 },
+       { 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 },
+       { 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 },
+       { 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 },
+       { 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da },
+       { 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db },
+       { 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc },
+       { 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd },
+       { 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de },
+       { 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df },
+       { 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 },
+       { 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 },
+       { 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 },
+       { 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 },
+       { 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 },
+       { 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 },
+       { 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 },
+       { 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 },
+       { 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 },
+       { 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 },
+       { 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea },
+       { 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb },
+       { 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec },
+       { 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed },
+       { 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee },
+       { 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef },
+       { 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 },
+       { 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 },
+       { 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 },
+       { 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 },
+       { 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 },
+       { 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 },
+       { 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 },
+       { 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 },
+       { 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 },
+       { 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 },
+       { 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa },
+       { 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb },
+       { 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc },
+       { 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd },
+       { 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe },
+       { 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff },
+       { 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 },
+       { 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 },
+       { 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 },
+       { 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 },
+       { 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 },
+       { 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 },
+       { 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 },
+       { 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 },
+       { 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 },
+       { 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 },
+       { 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a },
+       { 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b },
+       { 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c },
+       { 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d },
+       { 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e },
+       { 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f }
+};
+
+/**
+ * @brief   -------------------------------------------------
+ *            qoffsets - each row represents the addresses used to calculate a byte of the ECC Q
+ *            data 52 (*2) ECC Q bytes, 43 values represented by each
+ *          -------------------------------------------------.
+ */
+
+static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =
+{
+       { 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 },
+       { 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 },
+       { 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a },
+       { 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b },
+       { 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 },
+       { 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 },
+       { 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 },
+       { 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 },
+       { 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c },
+       { 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d },
+       { 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 },
+       { 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 },
+       { 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 },
+       { 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 },
+       { 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e },
+       { 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f },
+       { 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 },
+       { 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 },
+       { 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba },
+       { 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb },
+       { 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 },
+       { 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 },
+       { 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa },
+       { 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab },
+       { 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 },
+       { 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 },
+       { 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 },
+       { 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 },
+       { 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac },
+       { 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad },
+       { 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 },
+       { 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 },
+       { 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 },
+       { 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 },
+       { 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae },
+       { 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af },
+       { 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 },
+       { 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 },
+       { 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a },
+       { 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b },
+       { 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 },
+       { 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 },
+       { 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 },
+       { 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 },
+       { 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c },
+       { 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d },
+       { 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 },
+       { 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 },
+       { 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 },
+       { 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 },
+       { 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e },
+       { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f }
+};
+
+/*-------------------------------------------------
+ *  ecc_source_byte - return data from the sector
+ *  at the given offset, masking anything
+ *  particular to a mode
+ *-------------------------------------------------
+ */
+
+static INLINE uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
+{
+       /* in mode 2 always treat these as 0 bytes */
+       return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];
+}
+
+/**
+ * @fn  void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_compute_bytes - calculate an ECC value (P or Q)
+ *          -------------------------------------------------.
+ *
+ * @param   sector          The sector.
+ * @param   row             The row.
+ * @param   rowlen          The rowlen.
+ * @param [in,out]  val1    The first value.
+ * @param [in,out]  val2    The second value.
+ */
+
+void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)
+{
+   int component;
+       *val1 = *val2 = 0;
+       for (component = 0; component < rowlen; component++)
+       {
+               *val1 ^= ecc_source_byte(sector, row[component]);
+               *val2 ^= ecc_source_byte(sector, row[component]);
+               *val1 = ecclow[*val1];
+       }
+       *val1 = ecchigh[ecclow[*val1] ^ *val2];
+       *val2 ^= *val1;
+}
+
+/**
+ * @fn  int ecc_verify(const uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_verify - verify the P and Q ECC codes in a sector
+ *          -------------------------------------------------.
+ *
+ * @param   sector  The sector.
+ *
+ * @return  true if it succeeds, false if it fails.
+ */
+
+int ecc_verify(const uint8_t *sector)
+{
+   int byte;
+       /* first verify P bytes */
+       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
+       {
+               uint8_t val1, val2;
+               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2);
+               if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2)
+                       return 0;
+       }
+
+       /* then verify Q bytes */
+       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
+       {
+               uint8_t val1, val2;
+               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2);
+               if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2)
+                       return 0;
+       }
+       return 1;
+}
+
+/**
+ * @fn  void ecc_generate(uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_generate - generate the P and Q ECC codes for a sector, overwriting any
+ *            existing codes
+ *          -------------------------------------------------.
+ *
+ * @param [in,out]  sector  If non-null, the sector.
+ */
+
+void ecc_generate(uint8_t *sector)
+{
+   int byte;
+       /* first verify P bytes */
+       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
+               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);
+
+       /* then verify Q bytes */
+       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
+               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);
+}
+
+/**
+ * @fn  void ecc_clear(uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_clear - erase the ECC P and Q cods to 0 within a sector
+ *          -------------------------------------------------.
+ *
+ * @param [in,out]  sector  If non-null, the sector.
+ */
+
+void ecc_clear(uint8_t *sector)
+{
+       memset(&sector[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES);
+       memset(&sector[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES);
+}
+
+#endif /* WANT_RAW_DATA_SECTOR */
diff --git a/deps/libretro-common/formats/libchdr/libchdr_chd.c b/deps/libretro-common/formats/libchdr/libchdr_chd.c
new file mode 100644 (file)
index 0000000..9a157cc
--- /dev/null
@@ -0,0 +1,1939 @@
+/***************************************************************************
+
+    chd.c
+
+    MAME Compressed Hunks of Data file format
+
+****************************************************************************
+
+    Copyright Aaron Giles
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+        * 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 'MAME' 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 AARON GILES ''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 AARON GILES 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libchdr/chd.h>
+#include <libchdr/minmax.h>
+#include <libchdr/cdrom.h>
+#include <libchdr/huffman.h>
+
+#ifdef HAVE_FLAC
+#include <libchdr/flac.h>
+#endif
+
+#ifdef HAVE_7ZIP
+#include <libchdr/lzma.h>
+#endif
+
+#ifdef HAVE_ZLIB
+#include <libchdr/libchdr_zlib.h>
+#endif
+
+#include <retro_inline.h>
+#include <streams/file_stream.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/***************************************************************************
+    DEBUGGING
+***************************************************************************/
+
+#define PRINTF_MAX_HUNK                                (0)
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+#define MAP_STACK_ENTRIES                      512                     /* max number of entries to use on the stack */
+#define MAP_ENTRY_SIZE                         16                      /* V3 and later */
+#define OLD_MAP_ENTRY_SIZE                     8                       /* V1-V2 */
+#define METADATA_HEADER_SIZE           16                      /* metadata header size */
+
+#define CRCMAP_HASH_SIZE                       4095            /* number of CRC hashtable entries */
+
+#define MAP_ENTRY_FLAG_TYPE_MASK       0x0f            /* what type of hunk */
+#define MAP_ENTRY_FLAG_NO_CRC          0x10            /* no CRC is present */
+
+#define CHD_V1_SECTOR_SIZE                     512                     /* size of a "sector" in the V1 header */
+
+#define COOKIE_VALUE                           0xbaadf00d
+
+#define END_OF_LIST_COOKIE                     "EndOfListCookie"
+
+#define NO_MATCH                                       (~0)
+
+#ifdef WANT_RAW_DATA_SECTOR
+const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
+#endif
+
+/* V3-V4 entry types */
+enum
+{
+       V34_MAP_ENTRY_TYPE_INVALID = 0,             /* invalid type */
+       V34_MAP_ENTRY_TYPE_COMPRESSED = 1,          /* standard compression */
+       V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,        /* uncompressed data */
+       V34_MAP_ENTRY_TYPE_MINI = 3,                /* mini: use offset as raw data */
+       V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,           /* same as another hunk in this file */
+       V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         /* same as a hunk in the parent file */
+       V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6       /* compressed with secondary algorithm (usually FLAC CDDA) */
+};
+
+/* V5 compression types */
+enum
+{
+       /* codec #0
+        * these types are live when running */
+       COMPRESSION_TYPE_0 = 0,
+       /* codec #1 */
+       COMPRESSION_TYPE_1 = 1,
+       /* codec #2 */
+       COMPRESSION_TYPE_2 = 2,
+       /* codec #3 */
+       COMPRESSION_TYPE_3 = 3,
+       /* no compression; implicit length = hunkbytes */
+       COMPRESSION_NONE = 4,
+       /* same as another block in this chd */
+       COMPRESSION_SELF = 5,
+       /* same as a hunk's worth of units in the parent chd */
+       COMPRESSION_PARENT = 6,
+
+       /* start of small RLE run (4-bit length)
+        * these additional pseudo-types are used for compressed encodings: */
+       COMPRESSION_RLE_SMALL,
+       /* start of large RLE run (8-bit length) */
+       COMPRESSION_RLE_LARGE,
+       /* same as the last COMPRESSION_SELF block */
+       COMPRESSION_SELF_0,
+       /* same as the last COMPRESSION_SELF block + 1 */
+       COMPRESSION_SELF_1,
+       /* same block in the parent */
+       COMPRESSION_PARENT_SELF,
+       /* same as the last COMPRESSION_PARENT block */
+       COMPRESSION_PARENT_0,
+       /* same as the last COMPRESSION_PARENT block + 1 */
+       COMPRESSION_PARENT_1
+};
+
+/***************************************************************************
+    MACROS
+***************************************************************************/
+
+#define EARLY_EXIT(x)                          do { (void)(x); goto cleanup; } while (0)
+
+/***************************************************************************
+    TYPE DEFINITIONS
+***************************************************************************/
+
+/* interface to a codec */
+typedef struct _codec_interface codec_interface;
+struct _codec_interface
+{
+       UINT32          compression;                                                            /* type of compression */
+       const char *compname;                                                                   /* name of the algorithm */
+       UINT8           lossy;                                                                          /* is this a lossy algorithm? */
+       chd_error       (*init)(void *codec, UINT32 hunkbytes);         /* codec initialize */
+       void            (*free)(void *codec);                                           /* codec free */
+       chd_error       (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */
+       chd_error       (*config)(void *codec, int param, void *config); /* configure */
+};
+
+/* a single map entry */
+typedef struct _map_entry map_entry;
+struct _map_entry
+{
+       UINT64                                  offset;                 /* offset within the file of the data */
+       UINT32                                  crc;                    /* 32-bit CRC of the data */
+       UINT32                                  length;                 /* length of the data */
+       UINT8                                   flags;                  /* misc flags */
+};
+
+/* a single metadata entry */
+typedef struct _metadata_entry metadata_entry;
+struct _metadata_entry
+{
+       UINT64                                  offset;                 /* offset within the file of the header */
+       UINT64                                  next;                   /* offset within the file of the next header */
+       UINT64                                  prev;                   /* offset within the file of the previous header */
+       UINT32                                  length;                 /* length of the metadata */
+       UINT32                                  metatag;                /* metadata tag */
+       UINT8                                   flags;                  /* flag bits */
+};
+
+/* internal representation of an open CHD file */
+struct _chd_file
+{
+       UINT32                                  cookie;                 /* cookie, should equal COOKIE_VALUE */
+
+       RFILE *                         file;                   /* handle to the open core file */
+       UINT8                                   owns_file;              /* flag indicating if this file should be closed on chd_close() */
+       chd_header                              header;                 /* header, extracted from file */
+
+       chd_file *                              parent;                 /* pointer to parent file, or NULL */
+
+       map_entry *                             map;                    /* array of map entries */
+
+#ifdef NEED_CACHE_HUNK
+       UINT8 *                                 cache;                  /* hunk cache pointer */
+       UINT32                                  cachehunk;              /* index of currently cached hunk */
+
+       UINT8 *                                 compare;                /* hunk compare pointer */
+       UINT32                                  comparehunk;    /* index of current compare data */
+#endif
+
+       UINT8 *                                 compressed;             /* pointer to buffer for compressed data */
+       const codec_interface * codecintf[4];   /* interface to the codec */
+
+#ifdef HAVE_ZLIB
+       zlib_codec_data                 zlib_codec_data;                /* zlib codec data */
+       cdzl_codec_data                 cdzl_codec_data;                /* cdzl codec data */
+#endif
+#ifdef HAVE_7ZIP
+       cdlz_codec_data                 cdlz_codec_data;                /* cdlz codec data */
+#endif
+#ifdef HAVE_FLAC
+       cdfl_codec_data                 cdfl_codec_data;                /* cdfl codec data */
+#endif
+
+#ifdef NEED_CACHE_HUNK
+       UINT32                                  maxhunk;                /* maximum hunk accessed */
+#endif
+   UINT8 *              file_cache; /* cache of underlying file */
+};
+
+/***************************************************************************
+    GLOBAL VARIABLES
+***************************************************************************/
+
+static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
+static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
+
+/***************************************************************************
+    PROTOTYPES
+***************************************************************************/
+
+/* internal header operations */
+static chd_error header_validate(const chd_header *header);
+static chd_error header_read(chd_file *chd, chd_header *header);
+
+/* internal hunk read/write */
+#ifdef NEED_CACHE_HUNK
+static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
+#endif
+static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
+
+/* internal map access */
+static chd_error map_read(chd_file *chd);
+
+/* metadata management */
+static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
+
+/***************************************************************************
+    CODEC INTERFACES
+***************************************************************************/
+
+static const codec_interface codec_interfaces[] =
+{
+       /* "none" or no compression */
+       {
+               CHDCOMPRESSION_NONE,
+               "none",
+               FALSE,
+               NULL,
+               NULL,
+               NULL,
+               NULL
+       },
+
+#ifdef HAVE_ZLIB
+       /* standard zlib compression */
+       {
+               CHDCOMPRESSION_ZLIB,
+               "zlib",
+               FALSE,
+               zlib_codec_init,
+               zlib_codec_free,
+               zlib_codec_decompress,
+               NULL
+       },
+
+       /* zlib+ compression */
+       {
+               CHDCOMPRESSION_ZLIB_PLUS,
+               "zlib+",
+               FALSE,
+               zlib_codec_init,
+               zlib_codec_free,
+               zlib_codec_decompress,
+               NULL
+       },
+
+   /* V5 zlib compression */
+       {
+               CHD_CODEC_ZLIB,
+               "zlib (Deflate)",
+               FALSE,
+               zlib_codec_init,
+               zlib_codec_free,
+               zlib_codec_decompress,
+               NULL
+       },
+
+       /* V5 CD zlib compression */
+       {
+               CHD_CODEC_CD_ZLIB,
+               "cdzl (CD Deflate)",
+               FALSE,
+               cdzl_codec_init,
+               cdzl_codec_free,
+               cdzl_codec_decompress,
+               NULL
+       },
+#endif
+
+#ifdef HAVE_7ZIP
+       /* V5 CD lzma compression */
+       {
+               CHD_CODEC_CD_LZMA,
+               "cdlz (CD LZMA)",
+               FALSE,
+               cdlz_codec_init,
+               cdlz_codec_free,
+               cdlz_codec_decompress,
+               NULL
+       },
+#endif
+
+#ifdef HAVE_FLAC
+       /* V5 CD flac compression */
+       {
+               CHD_CODEC_CD_FLAC,
+               "cdfl (CD FLAC)",
+               FALSE,
+               cdfl_codec_init,
+               cdfl_codec_free,
+               cdfl_codec_decompress,
+               NULL
+       },
+#endif
+};
+
+/***************************************************************************
+    INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+    get_bigendian_uint64 - fetch a UINT64 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE UINT64 get_bigendian_uint64(const UINT8 *base)
+{
+       return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
+                       ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint64 - write a UINT64 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value)
+{
+       base[0] = value >> 56;
+       base[1] = value >> 48;
+       base[2] = value >> 40;
+       base[3] = value >> 32;
+       base[4] = value >> 24;
+       base[5] = value >> 16;
+       base[6] = value >> 8;
+       base[7] = value;
+}
+
+/*-------------------------------------------------
+    get_bigendian_uint48 - fetch a UINT48 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE UINT64 get_bigendian_uint48(const UINT8 *base)
+{
+       return  ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) |
+                       ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint48 - write a UINT48 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE void put_bigendian_uint48(UINT8 *base, UINT64 value)
+{
+       value &= 0xffffffffffff;
+       base[0] = value >> 40;
+       base[1] = value >> 32;
+       base[2] = value >> 24;
+       base[3] = value >> 16;
+       base[4] = value >> 8;
+       base[5] = value;
+}
+/*-------------------------------------------------
+    get_bigendian_uint32 - fetch a UINT32 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE UINT32 get_bigendian_uint32(const UINT8 *base)
+{
+       return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint32 - write a UINT32 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+#if 0
+static INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
+{
+   base[0] = value >> 24;
+       base[1] = value >> 16;
+       base[2] = value >> 8;
+       base[3] = value;
+}
+#endif
+
+/*-------------------------------------------------
+    put_bigendian_uint24 - write a UINT24 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value)
+{
+       value &= 0xffffff;
+       base[0] = value >> 16;
+       base[1] = value >> 8;
+       base[2] = value;
+}
+
+/*-------------------------------------------------
+    get_bigendian_uint24 - fetch a UINT24 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE UINT32 get_bigendian_uint24(const UINT8 *base)
+{
+       return (base[0] << 16) | (base[1] << 8) | base[2];
+}
+
+/*-------------------------------------------------
+    get_bigendian_uint16 - fetch a UINT16 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE UINT16 get_bigendian_uint16(const UINT8 *base)
+{
+       return (base[0] << 8) | base[1];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint16 - write a UINT16 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value)
+{
+       base[0] = value >> 8;
+       base[1] = value;
+}
+
+/*-------------------------------------------------
+    map_extract - extract a single map
+    entry from the datastream
+-------------------------------------------------*/
+
+static INLINE void map_extract(const UINT8 *base, map_entry *entry)
+{
+       entry->offset = get_bigendian_uint64(&base[0]);
+       entry->crc = get_bigendian_uint32(&base[8]);
+       entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
+       entry->flags = base[15];
+}
+
+/*-------------------------------------------------
+    map_assemble - write a single map
+    entry to the datastream
+-------------------------------------------------*/
+
+#if 0
+static INLINE void map_assemble(UINT8 *base, map_entry *entry)
+{
+       put_bigendian_uint64(&base[0], entry->offset);
+       put_bigendian_uint32(&base[8], entry->crc);
+       put_bigendian_uint16(&base[12], entry->length);
+       base[14] = entry->length >> 16;
+       base[15] = entry->flags;
+}
+#endif
+
+/*-------------------------------------------------
+    map_size_v5 - calculate CHDv5 map size
+-------------------------------------------------*/
+static INLINE int map_size_v5(chd_header* header)
+{
+       return header->hunkcount * header->mapentrybytes;
+}
+
+/*-------------------------------------------------
+    crc16 - calculate CRC16 (from hashing.cpp)
+-------------------------------------------------*/
+uint16_t crc16(const void *data, uint32_t length)
+{
+       uint16_t crc = 0xffff;
+
+       static const uint16_t s_table[256] =
+       {
+               0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+               0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+               0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+               0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+               0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+               0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+               0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+               0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+               0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+               0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+               0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+               0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+               0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+               0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+               0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+               0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+               0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+               0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+               0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+               0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+               0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+               0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+               0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+               0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+               0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+               0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+               0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+               0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+               0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+               0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+               0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+               0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+       };
+
+       const uint8_t *src = (uint8_t*)data;
+
+       /* fetch the current value into a local and rip through the source data */
+       while (length-- != 0)
+               crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
+       return crc;
+}
+
+/*-------------------------------------------------
+       decompress_v5_map - decompress the v5 map
+-------------------------------------------------*/
+
+static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
+{
+       uint8_t rawbuf[16];
+   uint16_t mapcrc;
+   uint32_t mapbytes;
+   uint64_t firstoffs;
+       uint32_t last_self = 0;
+       uint64_t last_parent = 0;
+       uint8_t lastcomp = 0;
+       int hunknum, repcount = 0;
+   enum huffman_error err;
+   uint8_t lengthbits, selfbits, parentbits;
+   uint8_t* compressed;
+   struct bitstream* bitbuf;
+   struct huffman_decoder* decoder;
+   uint64_t curoffset;
+       if (header->mapoffset == 0)
+       {
+#if 0
+               memset(header->rawmap, 0xff,map_size_v5(header));
+#endif
+               return CHDERR_READ_ERROR;
+       }
+
+       /* read the reader */
+       filestream_seek(chd->file, header->mapoffset, SEEK_SET);
+       filestream_read(chd->file, rawbuf, sizeof(rawbuf));
+       mapbytes = get_bigendian_uint32(&rawbuf[0]);
+       firstoffs = get_bigendian_uint48(&rawbuf[4]);
+       mapcrc = get_bigendian_uint16(&rawbuf[10]);
+       lengthbits = rawbuf[12];
+       selfbits = rawbuf[13];
+       parentbits = rawbuf[14];
+
+       /* now read the map */
+       compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
+       if (compressed == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       filestream_seek(chd->file, header->mapoffset + 16, SEEK_SET);
+       filestream_read(chd->file, compressed, mapbytes);
+       bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes);
+       if (bitbuf == NULL)
+       {
+               free(compressed);
+               return CHDERR_OUT_OF_MEMORY;
+       }
+
+       header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header));
+       if (header->rawmap == NULL)
+       {
+               free(compressed);
+               free(bitbuf);
+               return CHDERR_OUT_OF_MEMORY;
+       }
+
+       /* first decode the compression types */
+       decoder = create_huffman_decoder(16, 8);
+       if (decoder == NULL)
+       {
+               free(compressed);
+               free(bitbuf);
+               return CHDERR_OUT_OF_MEMORY;
+       }
+
+       err = huffman_import_tree_rle(decoder, bitbuf);
+       if (err != HUFFERR_NONE)
+       {
+               free(compressed);
+               free(bitbuf);
+               delete_huffman_decoder(decoder);
+               return CHDERR_DECOMPRESSION_ERROR;
+       }
+
+       for (hunknum = 0; hunknum < (int)header->hunkcount; hunknum++)
+       {
+               uint8_t *rawmap = header->rawmap + (hunknum * 12);
+               if (repcount > 0)
+        {
+            rawmap[0] = lastcomp;
+            repcount--;
+        }
+               else
+               {
+                       uint8_t val = huffman_decode_one(decoder, bitbuf);
+                       if (val == COMPRESSION_RLE_SMALL)
+            {
+                rawmap[0] = lastcomp;
+                repcount = 2 + huffman_decode_one(decoder, bitbuf);
+            }
+                       else if (val == COMPRESSION_RLE_LARGE)
+            {
+                rawmap[0] = lastcomp;
+                repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4);
+                repcount += huffman_decode_one(decoder, bitbuf);
+            }
+                       else
+                               rawmap[0] = lastcomp = val;
+               }
+       }
+
+       /* then iterate through the hunks and extract the needed data */
+       curoffset = firstoffs;
+       for (hunknum = 0; hunknum < (int)header->hunkcount; hunknum++)
+       {
+               uint8_t *rawmap = header->rawmap + (hunknum * 12);
+               uint64_t offset = curoffset;
+               uint32_t length = 0;
+               uint16_t crc = 0;
+               switch (rawmap[0])
+               {
+                       /* base types */
+                       case COMPRESSION_TYPE_0:
+                       case COMPRESSION_TYPE_1:
+                       case COMPRESSION_TYPE_2:
+                       case COMPRESSION_TYPE_3:
+                               curoffset += length = bitstream_read(bitbuf, lengthbits);
+                               crc = bitstream_read(bitbuf, 16);
+                               break;
+
+                       case COMPRESSION_NONE:
+                               curoffset += length = header->hunkbytes;
+                               crc = bitstream_read(bitbuf, 16);
+                               break;
+
+                       case COMPRESSION_SELF:
+                               last_self = offset = bitstream_read(bitbuf, selfbits);
+                               break;
+
+                       case COMPRESSION_PARENT:
+                               offset = bitstream_read(bitbuf, parentbits);
+                               last_parent = offset;
+                               break;
+
+                       /* pseudo-types; convert into base types */
+                       case COMPRESSION_SELF_1:
+                               last_self++;
+                       case COMPRESSION_SELF_0:
+                               rawmap[0] = COMPRESSION_SELF;
+                               offset = last_self;
+                               break;
+
+                       case COMPRESSION_PARENT_SELF:
+                               rawmap[0] = COMPRESSION_PARENT;
+                               last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;
+                               break;
+
+                       case COMPRESSION_PARENT_1:
+                               last_parent += header->hunkbytes / header->unitbytes;
+                       case COMPRESSION_PARENT_0:
+                               rawmap[0] = COMPRESSION_PARENT;
+                               offset = last_parent;
+                               break;
+               }
+               /* UINT24 length */
+               put_bigendian_uint24(&rawmap[1], length);
+
+               /* UINT48 offset */
+               put_bigendian_uint48(&rawmap[4], offset);
+
+               /* crc16 */
+               put_bigendian_uint16(&rawmap[10], crc);
+       }
+
+       /* free memory */
+       free(compressed);
+       free(bitbuf);
+       delete_huffman_decoder(decoder);
+
+       /* verify the final CRC */
+       if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    map_extract_old - extract a single map
+    entry in old format from the datastream
+-------------------------------------------------*/
+
+static INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
+{
+       entry->offset = get_bigendian_uint64(&base[0]);
+       entry->crc = 0;
+       entry->length = entry->offset >> 44;
+       entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
+#ifdef __MWERKS__
+       entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
+#else
+       entry->offset = (entry->offset << 20) >> 20;
+#endif
+}
+
+/***************************************************************************
+    CHD FILE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_open_file - open a CHD file for access
+-------------------------------------------------*/
+
+chd_error chd_open_file(RFILE *file, int mode, chd_file *parent, chd_file **chd)
+{
+       chd_file *newchd = NULL;
+       chd_error err;
+       int intfnum;
+
+       /* verify parameters */
+       if (file == NULL)
+               EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+       /* punt if invalid parent */
+       if (parent != NULL && parent->cookie != COOKIE_VALUE)
+               EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+       /* allocate memory for the final result */
+       newchd = (chd_file *)malloc(sizeof(**chd));
+       if (newchd == NULL)
+               EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+       memset(newchd, 0, sizeof(*newchd));
+       newchd->cookie = COOKIE_VALUE;
+       newchd->parent = parent;
+       newchd->file = file;
+
+       /* now attempt to read the header */
+       err = header_read(newchd, &newchd->header);
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+       /* validate the header */
+       err = header_validate(&newchd->header);
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+       /* make sure we don't open a read-only file writeable */
+       if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
+               EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);
+
+       /* also, never open an older version writeable */
+       if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
+               EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
+
+       /* if we need a parent, make sure we have one */
+       if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT))
+               EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
+
+       /* make sure we have a valid parent */
+       if (parent != NULL)
+       {
+               /* check MD5 if it isn't empty */
+               if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
+                       memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
+                       memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
+                       EARLY_EXIT(err = CHDERR_INVALID_PARENT);
+
+               /* check SHA1 if it isn't empty */
+               if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
+                       memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
+                       memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
+                       EARLY_EXIT(err = CHDERR_INVALID_PARENT);
+       }
+
+       /* now read the hunk map */
+       if (newchd->header.version < 5)
+       {
+               err = map_read(newchd);
+       }
+       else
+       {
+               err = decompress_v5_map(newchd, &(newchd->header));
+       }
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+#ifdef NEED_CACHE_HUNK
+       /* allocate and init the hunk cache */
+       newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes);
+       newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes);
+       if (newchd->cache == NULL || newchd->compare == NULL)
+               EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+       newchd->cachehunk = ~0;
+       newchd->comparehunk = ~0;
+#endif
+
+       /* allocate the temporary compressed buffer */
+       newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes);
+       if (newchd->compressed == NULL)
+               EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+
+       /* find the codec interface */
+       if (newchd->header.version < 5)
+       {
+               for (intfnum = 0; intfnum < (int)ARRAY_SIZE(codec_interfaces); intfnum++)
+                       if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
+                       {
+                               newchd->codecintf[0] = &codec_interfaces[intfnum];
+                               break;
+                       }
+               if (intfnum == ARRAY_SIZE(codec_interfaces))
+                       EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
+
+#ifdef HAVE_ZLIB
+               /* initialize the codec */
+               if (newchd->codecintf[0]->init != NULL)
+      {
+         err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
+         (void)err;
+      }
+#endif
+       }
+       else
+       {
+               int i, decompnum;
+               /* verify the compression types and initialize the codecs */
+               for (decompnum = 0; decompnum < (int)ARRAY_SIZE(newchd->header.compression); decompnum++)
+               {
+                       for (i = 0 ; i < (int)ARRAY_SIZE(codec_interfaces); i++)
+                       {
+                               if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
+                               {
+                                       newchd->codecintf[decompnum] = &codec_interfaces[i];
+                                       if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
+                    {
+                                               err = CHDERR_UNSUPPORTED_FORMAT;
+                        (void)err;
+                    }
+
+                                       /* initialize the codec */
+                                       if (newchd->codecintf[decompnum]->init != NULL)
+                                       {
+                                               void* codec = NULL;
+                                               switch (newchd->header.compression[decompnum])
+                                               {
+                     case CHD_CODEC_ZLIB:
+#ifdef HAVE_ZLIB
+                                                               codec = &newchd->zlib_codec_data;
+#endif
+                                                               break;
+
+                                                       case CHD_CODEC_CD_ZLIB:
+#ifdef HAVE_ZLIB
+                                                               codec = &newchd->cdzl_codec_data;
+#endif
+                                                               break;
+
+                                                       case CHD_CODEC_CD_LZMA:
+#ifdef HAVE_7ZIP
+                                                               codec = &newchd->cdlz_codec_data;
+#endif
+                                                               break;
+
+                                                       case CHD_CODEC_CD_FLAC:
+#ifdef HAVE_FLAC
+                                                               codec = &newchd->cdfl_codec_data;
+#endif
+                                                               break;
+                                               }
+                                               if (codec != NULL)
+                        {
+                                                       err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
+                            (void)err;
+                        }
+                                       }
+
+                               }
+                       }
+               }
+       }
+
+#if 0
+       /* HACK */
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+#endif
+
+       /* all done */
+       *chd = newchd;
+       return CHDERR_NONE;
+
+cleanup:
+       if (newchd != NULL)
+               chd_close(newchd);
+       return err;
+}
+
+/*-------------------------------------------------
+    chd_precache - precache underlying file in
+    memory
+-------------------------------------------------*/
+
+chd_error chd_precache(chd_file *chd)
+{
+       int64_t size, count;
+
+       if (!chd->file_cache)
+       {
+               filestream_seek(chd->file, 0, SEEK_END);
+               size = filestream_tell(chd->file);
+               if (size <= 0)
+                       return CHDERR_INVALID_DATA;
+               chd->file_cache = (UINT8*)malloc(size);
+               if (chd->file_cache == NULL)
+                       return CHDERR_OUT_OF_MEMORY;
+               filestream_seek(chd->file, 0, SEEK_SET);
+               count = filestream_read(chd->file, chd->file_cache, size);
+               if (count != size)
+               {
+                       free(chd->file_cache);
+                       chd->file_cache = NULL;
+                       return CHDERR_READ_ERROR;
+               }
+       }
+
+       return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+    chd_open - open a CHD file by
+    filename
+-------------------------------------------------*/
+
+chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
+{
+       chd_error err;
+       RFILE *file = NULL;
+
+       /* choose the proper mode */
+       switch(mode)
+       {
+               case CHD_OPEN_READ:
+                       break;
+
+               default:
+                       err = CHDERR_INVALID_PARAMETER;
+                       goto cleanup;
+       }
+
+       /* open the file */
+       file = filestream_open(filename,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+       if (!file)
+       {
+               err = CHDERR_FILE_NOT_FOUND;
+               goto cleanup;
+       }
+
+       /* now open the CHD */
+       err = chd_open_file(file, mode, parent, chd);
+       if (err != CHDERR_NONE)
+               goto cleanup;
+
+       /* we now own this file */
+       (*chd)->owns_file = TRUE;
+
+cleanup:
+       if ((err != CHDERR_NONE) && (file != NULL))
+               filestream_close(file);
+       return err;
+}
+
+/*-------------------------------------------------
+    chd_close - close a CHD file for access
+-------------------------------------------------*/
+
+void chd_close(chd_file *chd)
+{
+       /* punt if NULL or invalid */
+       if (chd == NULL || chd->cookie != COOKIE_VALUE)
+               return;
+
+       /* deinit the codec */
+       if (chd->header.version < 5)
+       {
+#ifdef HAVE_ZLIB
+               if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
+                       (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
+#endif
+       }
+       else
+       {
+               int i;
+               /* Free the codecs */
+               for (i = 0 ; i < 4 ; i++)
+      {
+         void* codec = NULL;
+         if (!chd->codecintf[i])
+            continue;
+
+         switch (chd->codecintf[i]->compression)
+         {
+            case CHD_CODEC_CD_LZMA:
+#ifdef HAVE_7ZIP
+               codec = &chd->cdlz_codec_data;
+#endif
+               break;
+
+            case CHD_CODEC_ZLIB:
+#ifdef HAVE_ZLIB
+               codec = &chd->zlib_codec_data;
+#endif
+               break;
+
+            case CHD_CODEC_CD_ZLIB:
+#ifdef HAVE_ZLIB
+               codec = &chd->cdzl_codec_data;
+#endif
+               break;
+
+            case CHD_CODEC_CD_FLAC:
+#ifdef HAVE_FLAC
+               codec = &chd->cdfl_codec_data;
+#endif
+               break;
+         }
+         if (codec)
+            (*chd->codecintf[i]->free)(codec);
+      }
+
+               /* Free the raw map */
+               if (chd->header.rawmap != NULL)
+                       free(chd->header.rawmap);
+       }
+
+       /* free the compressed data buffer */
+       if (chd->compressed != NULL)
+               free(chd->compressed);
+
+#ifdef NEED_CACHE_HUNK
+       /* free the hunk cache and compare data */
+       if (chd->compare != NULL)
+               free(chd->compare);
+       if (chd->cache != NULL)
+               free(chd->cache);
+#endif
+
+       /* free the hunk map */
+       if (chd->map != NULL)
+               free(chd->map);
+
+       /* close the file */
+       if (chd->owns_file && chd->file != NULL)
+               filestream_close(chd->file);
+
+#ifdef NEED_CACHE_HUNK
+       if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
+#endif
+
+   if (chd->file_cache)
+      free(chd->file_cache);
+
+       /* free our memory */
+       free(chd);
+}
+
+/*-------------------------------------------------
+    chd_core_file - return the associated
+    core_file
+-------------------------------------------------*/
+
+RFILE *chd_core_file(chd_file *chd)
+{
+       return chd->file;
+}
+
+/*-------------------------------------------------
+    chd_error_string - return an error string for
+    the given CHD error
+-------------------------------------------------*/
+
+const char *chd_error_string(chd_error err)
+{
+       switch (err)
+       {
+               case CHDERR_NONE:                                               return "no error";
+               case CHDERR_NO_INTERFACE:                               return "no drive interface";
+               case CHDERR_OUT_OF_MEMORY:                              return "out of memory";
+               case CHDERR_INVALID_FILE:                               return "invalid file";
+               case CHDERR_INVALID_PARAMETER:                  return "invalid parameter";
+               case CHDERR_INVALID_DATA:                               return "invalid data";
+               case CHDERR_FILE_NOT_FOUND:                             return "file not found";
+               case CHDERR_REQUIRES_PARENT:                    return "requires parent";
+               case CHDERR_FILE_NOT_WRITEABLE:                 return "file not writeable";
+               case CHDERR_READ_ERROR:                                 return "read error";
+               case CHDERR_WRITE_ERROR:                                return "write error";
+               case CHDERR_CODEC_ERROR:                                return "codec error";
+               case CHDERR_INVALID_PARENT:                             return "invalid parent";
+               case CHDERR_HUNK_OUT_OF_RANGE:                  return "hunk out of range";
+               case CHDERR_DECOMPRESSION_ERROR:                return "decompression error";
+               case CHDERR_COMPRESSION_ERROR:                  return "compression error";
+               case CHDERR_CANT_CREATE_FILE:                   return "can't create file";
+               case CHDERR_CANT_VERIFY:                                return "can't verify file";
+               case CHDERR_NOT_SUPPORTED:                              return "operation not supported";
+               case CHDERR_METADATA_NOT_FOUND:                 return "can't find metadata";
+               case CHDERR_INVALID_METADATA_SIZE:              return "invalid metadata size";
+               case CHDERR_UNSUPPORTED_VERSION:                return "unsupported CHD version";
+               case CHDERR_VERIFY_INCOMPLETE:                  return "incomplete verify";
+               case CHDERR_INVALID_METADATA:                   return "invalid metadata";
+               case CHDERR_INVALID_STATE:                              return "invalid state";
+               case CHDERR_OPERATION_PENDING:                  return "operation pending";
+               case CHDERR_NO_ASYNC_OPERATION:                 return "no async operation in progress";
+               case CHDERR_UNSUPPORTED_FORMAT:                 return "unsupported format";
+               default:                                                                return "undocumented error";
+       }
+}
+
+/***************************************************************************
+    CHD HEADER MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_get_header - return a pointer to the
+    extracted header data
+-------------------------------------------------*/
+
+const chd_header *chd_get_header(chd_file *chd)
+{
+       /* punt if NULL or invalid */
+       if (chd == NULL || chd->cookie != COOKIE_VALUE)
+               return NULL;
+
+       return &chd->header;
+}
+
+/***************************************************************************
+    CORE DATA READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_read - read a single hunk from the CHD
+    file
+-------------------------------------------------*/
+
+chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
+{
+       /* punt if NULL or invalid */
+       if (chd == NULL || chd->cookie != COOKIE_VALUE)
+               return CHDERR_INVALID_PARAMETER;
+
+       /* perform the read */
+       return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
+}
+
+/***************************************************************************
+    METADATA MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_get_metadata - get the indexed metadata
+    of the given type
+-------------------------------------------------*/
+
+chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags)
+{
+       metadata_entry metaentry;
+       chd_error err;
+       int64_t count;
+
+       /* if we didn't find it, just return */
+       err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
+       if (err != CHDERR_NONE)
+       {
+               /* unless we're an old version and they are requesting hard disk metadata */
+               if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
+               {
+                       char faux_metadata[256];
+                       UINT32 faux_length;
+
+                       /* fill in the faux metadata */
+                       snprintf(faux_metadata,
+               sizeof(faux_metadata),
+               HARD_DISK_METADATA_FORMAT,
+               chd->header.obsolete_cylinders,
+               chd->header.obsolete_heads,
+               chd->header.obsolete_sectors,
+               chd->header.hunkbytes / chd->header.obsolete_hunksize);
+                       faux_length = (UINT32)strlen(faux_metadata) + 1;
+
+                       /* copy the metadata itself */
+                       memcpy(output, faux_metadata, MIN(outputlen, faux_length));
+
+                       /* return the length of the data and the tag */
+                       if (resultlen != NULL)
+                               *resultlen = faux_length;
+                       if (resulttag != NULL)
+                               *resulttag = HARD_DISK_METADATA_TAG;
+                       return CHDERR_NONE;
+               }
+               return err;
+       }
+
+       /* read the metadata */
+       outputlen = MIN(outputlen, metaentry.length);
+       filestream_seek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
+       count = filestream_read(chd->file, output, outputlen);
+       if (count != outputlen)
+               return CHDERR_READ_ERROR;
+
+       /* return the length of the data and the tag */
+       if (resultlen != NULL)
+               *resultlen = metaentry.length;
+       if (resulttag != NULL)
+               *resulttag = metaentry.metatag;
+       if (resultflags != NULL)
+               *resultflags = metaentry.flags;
+       return CHDERR_NONE;
+}
+
+/***************************************************************************
+    CODEC INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_codec_config - set internal codec
+    parameters
+-------------------------------------------------*/
+
+chd_error chd_codec_config(chd_file *chd, int param, void *config)
+{
+       return CHDERR_INVALID_PARAMETER;
+}
+
+/*-------------------------------------------------
+    chd_get_codec_name - get the name of a
+    particular codec
+-------------------------------------------------*/
+
+const char *chd_get_codec_name(UINT32 codec)
+{
+       return "Unknown";
+}
+
+/***************************************************************************
+    INTERNAL HEADER OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+    header_validate - check the validity of a
+    CHD header
+-------------------------------------------------*/
+
+static chd_error header_validate(const chd_header *header)
+{
+       int intfnum;
+
+       /* require a valid version */
+       if (header->version == 0 || header->version > CHD_HEADER_VERSION)
+               return CHDERR_UNSUPPORTED_VERSION;
+
+       /* require a valid length */
+       if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
+               (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
+               (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
+               (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
+               (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
+               return CHDERR_INVALID_PARAMETER;
+
+       /* Do not validate v5 header */
+       if (header->version <= 4)
+       {
+               /* require valid flags */
+               if (header->flags & CHDFLAGS_UNDEFINED)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a supported compression mechanism */
+               for (intfnum = 0; intfnum < (int)ARRAY_SIZE(codec_interfaces); intfnum++)
+                       if (codec_interfaces[intfnum].compression == header->compression[0])
+                               break;
+
+               if (intfnum == ARRAY_SIZE(codec_interfaces))
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a valid hunksize */
+               if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a valid hunk count */
+               if (header->totalhunks == 0)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a valid MD5 and/or SHA1 if we're using a parent */
+               if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* if we're V3 or later, the obsolete fields must be 0 */
+               if (header->version >= 3 &&
+                       (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
+                        header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* if we're pre-V3, the obsolete fields must NOT be 0 */
+               if (header->version < 3 &&
+                       (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
+                        header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
+                       return CHDERR_INVALID_PARAMETER;
+       }
+
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    header_guess_unitbytes - for older CHD formats,
+    guess at the bytes/unit based on metadata
+-------------------------------------------------*/
+
+static UINT32 header_guess_unitbytes(chd_file *chd)
+{
+       /* look for hard disk metadata; if found, then the unit size == sector size */
+       char metadata[512];
+       unsigned int i0, i1, i2, i3;
+       if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&
+               sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
+               return i3;
+
+       /* look for CD-ROM metadata; if found, then the unit size == CD frame size */
+       if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+      chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
+               return CD_FRAME_SIZE;
+
+       /* otherwise, just map 1:1 with the hunk size */
+       return chd->header.hunkbytes;
+}
+
+/*-------------------------------------------------
+    header_read - read a CHD header into the
+    internal data structure
+-------------------------------------------------*/
+
+static chd_error header_read(chd_file *chd, chd_header *header)
+{
+       UINT8 rawheader[CHD_MAX_HEADER_SIZE];
+       int64_t count;
+
+       /* punt if NULL */
+       if (header == NULL)
+               return CHDERR_INVALID_PARAMETER;
+
+       /* punt if invalid file */
+       if (chd->file == NULL)
+               return CHDERR_INVALID_FILE;
+
+       /* seek and read */
+       filestream_seek(chd->file, 0, SEEK_SET);
+       count = filestream_read(chd->file, rawheader, sizeof(rawheader));
+       if (count != sizeof(rawheader))
+               return CHDERR_READ_ERROR;
+
+       /* verify the tag */
+       if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
+               return CHDERR_INVALID_DATA;
+
+       /* extract the direct data */
+       memset(header, 0, sizeof(*header));
+       header->length        = get_bigendian_uint32(&rawheader[8]);
+       header->version       = get_bigendian_uint32(&rawheader[12]);
+
+       /* make sure it's a version we understand */
+       if (header->version == 0 || header->version > CHD_HEADER_VERSION)
+               return CHDERR_UNSUPPORTED_VERSION;
+
+       /* make sure the length is expected */
+       if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
+               (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
+               (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
+               (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
+               (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
+
+               return CHDERR_INVALID_DATA;
+
+       /* extract the common data */
+       header->flags           = get_bigendian_uint32(&rawheader[16]);
+       header->compression[0]  = get_bigendian_uint32(&rawheader[20]);
+
+       /* extract the V1/V2-specific data */
+       if (header->version < 3)
+       {
+               int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]);
+               header->obsolete_hunksize  = get_bigendian_uint32(&rawheader[24]);
+               header->totalhunks         = get_bigendian_uint32(&rawheader[28]);
+               header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
+               header->obsolete_heads     = get_bigendian_uint32(&rawheader[36]);
+               header->obsolete_sectors   = get_bigendian_uint32(&rawheader[40]);
+               memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
+               memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
+               header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
+               header->hunkbytes = seclen * header->obsolete_hunksize;
+               header->unitbytes          = header_guess_unitbytes(chd);
+               header->unitcount          = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               header->metaoffset = 0;
+       }
+
+       /* extract the V3-specific data */
+       else if (header->version == 3)
+       {
+               header->totalhunks   = get_bigendian_uint32(&rawheader[24]);
+               header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
+               header->metaoffset   = get_bigendian_uint64(&rawheader[36]);
+               memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
+               memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
+               header->hunkbytes    = get_bigendian_uint32(&rawheader[76]);
+               header->unitbytes    = header_guess_unitbytes(chd);
+               header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
+               memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
+       }
+
+       /* extract the V4-specific data */
+       else if (header->version == 4)
+       {
+               header->totalhunks   = get_bigendian_uint32(&rawheader[24]);
+               header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
+               header->metaoffset   = get_bigendian_uint64(&rawheader[36]);
+               header->hunkbytes    = get_bigendian_uint32(&rawheader[44]);
+               header->unitbytes    = header_guess_unitbytes(chd);
+               header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
+               memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
+               memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
+       }
+
+       /* extract the V5-specific data */
+       else if (header->version == 5)
+       {
+               /* TODO */
+               header->compression[0]  = get_bigendian_uint32(&rawheader[16]);
+               header->compression[1]  = get_bigendian_uint32(&rawheader[20]);
+               header->compression[2]  = get_bigendian_uint32(&rawheader[24]);
+               header->compression[3]  = get_bigendian_uint32(&rawheader[28]);
+               header->logicalbytes    = get_bigendian_uint64(&rawheader[32]);
+               header->mapoffset       = get_bigendian_uint64(&rawheader[40]);
+               header->metaoffset      = get_bigendian_uint64(&rawheader[48]);
+               header->hunkbytes       = get_bigendian_uint32(&rawheader[56]);
+               header->hunkcount       = (UINT32)((header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes);
+               header->unitbytes       = get_bigendian_uint32(&rawheader[60]);
+               header->unitcount       = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);
+               memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
+               memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);
+
+               /* determine properties of map entries */
+               header->mapentrybytes = 12; /* TODO compressed() ? 12 : 4; */
+
+               /* hack */
+               header->totalhunks              = header->hunkcount;
+       }
+
+       /* Unknown version */
+       else
+       {
+               /* TODO */
+       }
+
+       /* guess it worked */
+       return CHDERR_NONE;
+}
+
+/***************************************************************************
+    INTERNAL HUNK READ/WRITE
+***************************************************************************/
+
+#ifdef NEED_CACHE_HUNK
+/*-------------------------------------------------
+    hunk_read_into_cache - read a hunk into
+    the CHD's hunk cache
+-------------------------------------------------*/
+
+static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
+{
+       chd_error err;
+
+       /* track the max */
+       if (hunknum > chd->maxhunk)
+               chd->maxhunk = hunknum;
+
+       /* if we're already in the cache, we're done */
+       if (chd->cachehunk == hunknum)
+               return CHDERR_NONE;
+       chd->cachehunk = ~0;
+
+       /* otherwise, read the data */
+       err = hunk_read_into_memory(chd, hunknum, chd->cache);
+       if (err != CHDERR_NONE)
+               return err;
+
+       /* mark the hunk successfully cached in */
+       chd->cachehunk = hunknum;
+       return CHDERR_NONE;
+}
+#endif
+
+/*-------------------------------------------------
+    hunk_read_compressed - read a compressed
+    hunk
+-------------------------------------------------*/
+
+static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
+{
+   int64_t bytes;
+   if (chd->file_cache)
+      return chd->file_cache + offset;
+   filestream_seek(chd->file, offset, SEEK_SET);
+   bytes = filestream_read(chd->file, chd->compressed, size);
+   if (bytes != (int64_t)size)
+      return NULL;
+   return chd->compressed;
+}
+
+/*-------------------------------------------------
+    hunk_read_uncompressed - read an uncompressed
+    hunk
+-------------------------------------------------*/
+
+static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
+{
+   int64_t bytes;
+   if (chd->file_cache)
+   {
+      memcpy(dest, chd->file_cache + offset, size);
+      return CHDERR_NONE;
+   }
+   filestream_seek(chd->file, offset, SEEK_SET);
+   bytes = filestream_read(chd->file, dest, size);
+   if (bytes != (int64_t)size)
+      return CHDERR_READ_ERROR;
+   return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    hunk_read_into_memory - read a hunk into
+    memory at the given location
+-------------------------------------------------*/
+
+static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
+{
+       chd_error err;
+
+       /* punt if no file */
+       if (chd->file == NULL)
+               return CHDERR_INVALID_FILE;
+
+       /* return an error if out of range */
+       if (hunknum >= chd->header.totalhunks)
+               return CHDERR_HUNK_OUT_OF_RANGE;
+
+       if (dest == NULL)
+               return CHDERR_INVALID_PARAMETER;
+
+       if (chd->header.version < 5)
+       {
+               map_entry *entry = &chd->map[hunknum];
+               UINT32 bytes;
+      UINT8* compressed_bytes;
+
+               /* switch off the entry type */
+               switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
+               {
+                       /* compressed data */
+                       case V34_MAP_ENTRY_TYPE_COMPRESSED:
+            {
+               /* read it into the decompression buffer */
+
+               void *codec;
+               compressed_bytes = hunk_read_compressed(chd, entry->offset,
+                     entry->length);
+               if (compressed_bytes == NULL)
+                  return CHDERR_READ_ERROR;
+
+#ifdef HAVE_ZLIB
+               /* now decompress using the codec */
+               err   = CHDERR_NONE;
+               codec = &chd->zlib_codec_data;
+               if (chd->codecintf[0]->decompress != NULL)
+                  err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
+               if (err != CHDERR_NONE)
+                  return err;
+#endif
+            }
+                               break;
+
+                       /* uncompressed data */
+                       case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
+            err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
+            if (err != CHDERR_NONE)
+               return err;
+                               break;
+
+                       /* mini-compressed data */
+                       case V34_MAP_ENTRY_TYPE_MINI:
+                               put_bigendian_uint64(&dest[0], entry->offset);
+                               for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
+                                       dest[bytes] = dest[bytes - 8];
+                               break;
+
+                       /* self-referenced data */
+                       case V34_MAP_ENTRY_TYPE_SELF_HUNK:
+#ifdef NEED_CACHE_HUNK
+                               if (chd->cachehunk == entry->offset && dest == chd->cache)
+                                       break;
+#endif
+                               return hunk_read_into_memory(chd, (UINT32)entry->offset, dest);
+
+                       /* parent-referenced data */
+                       case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
+                               err = hunk_read_into_memory(chd->parent, (UINT32)entry->offset, dest);
+                               if (err != CHDERR_NONE)
+                                       return err;
+                               break;
+               }
+               return CHDERR_NONE;
+       }
+       else
+       {
+               void* codec = NULL;
+               /* get a pointer to the map entry */
+               uint64_t blockoffs;
+               uint32_t blocklen;
+#ifdef VERIFY_BLOCK_CRC
+               uint16_t blockcrc;
+#endif
+               uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
+      UINT8 *compressed_bytes;
+
+#if 0
+               /* uncompressed case - TODO */
+               if (!compressed())
+               {
+                       blockoffs = uint64_t(be_read(rawmap, 4)) * uint64_t(m_hunkbytes);
+                       if (blockoffs != 0)
+                               file_read(blockoffs, dest, m_hunkbytes);
+                       else if (m_parent_missing)
+                               throw CHDERR_REQUIRES_PARENT;
+                       else if (m_parent != nullptr)
+                               m_parent->read_hunk(hunknum, dest);
+                       else
+                               memset(dest, 0, m_hunkbytes);
+                       return CHDERR_NONE;
+               }
+#endif
+
+               /* compressed case */
+               blocklen  = get_bigendian_uint24(&rawmap[1]);
+               blockoffs = get_bigendian_uint48(&rawmap[4]);
+#ifdef VERIFY_BLOCK_CRC
+               blockcrc  = get_bigendian_uint16(&rawmap[10]);
+#endif
+               switch (rawmap[0])
+               {
+                       case COMPRESSION_TYPE_0:
+                       case COMPRESSION_TYPE_1:
+                       case COMPRESSION_TYPE_2:
+                       case COMPRESSION_TYPE_3:
+            compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
+            if (compressed_bytes == NULL)
+               return CHDERR_READ_ERROR;
+            if (!chd->codecintf[rawmap[0]])
+               return CHDERR_UNSUPPORTED_FORMAT;
+                               switch (chd->codecintf[rawmap[0]]->compression)
+                               {
+                                       case CHD_CODEC_CD_LZMA:
+#ifdef HAVE_7ZIP
+                                               codec = &chd->cdlz_codec_data;
+#endif
+                                               break;
+
+               case CHD_CODEC_ZLIB:
+#ifdef HAVE_ZLIB
+                  codec = &chd->zlib_codec_data;
+#endif
+                  break;
+
+                                       case CHD_CODEC_CD_ZLIB:
+#ifdef HAVE_ZLIB
+                                               codec = &chd->cdzl_codec_data;
+#endif
+                                               break;
+
+                                       case CHD_CODEC_CD_FLAC:
+#ifdef HAVE_FLAC
+                                               codec = &chd->cdfl_codec_data;
+#endif
+                                               break;
+                               }
+                               if (codec==NULL)
+                                       return CHDERR_CODEC_ERROR;
+                               err = (*chd->codecintf[rawmap[0]]->decompress)(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
+                               if (err != CHDERR_NONE)
+                                       return err;
+#ifdef VERIFY_BLOCK_CRC
+                               if (crc16(dest, chd->header.hunkbytes) != blockcrc)
+                                       return CHDERR_DECOMPRESSION_ERROR;
+#endif
+                               return CHDERR_NONE;
+
+                       case COMPRESSION_NONE:
+            err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
+            if (err != CHDERR_NONE)
+               return err;
+#ifdef VERIFY_BLOCK_CRC
+            if (crc16(dest, chd->header.hunkbytes) != blockcrc)
+               return CHDERR_DECOMPRESSION_ERROR;
+#endif
+                               return CHDERR_NONE;
+
+                       case COMPRESSION_SELF:
+                               return hunk_read_into_memory(chd, (UINT32)blockoffs, dest);
+
+                       case COMPRESSION_PARENT:
+#if 0
+                               /* TODO */
+                               if (m_parent_missing)
+                                       return CHDERR_REQUIRES_PARENT;
+                               return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
+#endif
+                               return CHDERR_DECOMPRESSION_ERROR;
+               }
+               return CHDERR_NONE;
+       }
+
+       /* We should not reach this code */
+       return CHDERR_DECOMPRESSION_ERROR;
+}
+
+/***************************************************************************
+    INTERNAL MAP ACCESS
+***************************************************************************/
+
+static size_t core_fsize(RFILE *f)
+{
+   int64_t rv, p = filestream_tell(f);
+       filestream_seek(f, 0, SEEK_END);
+       rv = filestream_tell(f);
+       filestream_seek(f, p, SEEK_SET);
+       return rv;
+}
+
+/*-------------------------------------------------
+    map_read - read the initial sector map
+-------------------------------------------------*/
+
+static chd_error map_read(chd_file *chd)
+{
+       UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
+       UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
+       UINT64 fileoffset, maxoffset = 0;
+       UINT8 cookie[MAP_ENTRY_SIZE];
+       int64_t count;
+       chd_error err;
+       int i;
+
+       /* first allocate memory */
+       chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
+       if (!chd->map)
+               return CHDERR_OUT_OF_MEMORY;
+
+       /* read the map entries in in chunks and extract to the map list */
+       fileoffset = chd->header.length;
+       for (i = 0; i < (int)chd->header.totalhunks; i += MAP_STACK_ENTRIES)
+       {
+               /* compute how many entries this time */
+               int entries = chd->header.totalhunks - i, j;
+               if (entries > MAP_STACK_ENTRIES)
+                       entries = MAP_STACK_ENTRIES;
+
+               /* read that many */
+               filestream_seek(chd->file, fileoffset, SEEK_SET);
+               count = filestream_read(chd->file, raw_map_entries, entries * entrysize);
+               if (count != entries * entrysize)
+               {
+                       err = CHDERR_READ_ERROR;
+                       goto cleanup;
+               }
+               fileoffset += entries * entrysize;
+
+               /* process that many */
+               if (entrysize == MAP_ENTRY_SIZE)
+               {
+                       for (j = 0; j < entries; j++)
+                               map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
+               }
+               else
+               {
+                       for (j = 0; j < entries; j++)
+                               map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
+               }
+
+               /* track the maximum offset */
+               for (j = 0; j < entries; j++)
+                       if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
+                               (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
+                               maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
+       }
+
+       /* verify the cookie */
+       filestream_seek(chd->file, fileoffset, SEEK_SET);
+       count = filestream_read(chd->file, &cookie, entrysize);
+       if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
+       {
+               err = CHDERR_INVALID_FILE;
+               goto cleanup;
+       }
+
+       /* verify the length */
+       if (maxoffset > core_fsize(chd->file))
+       {
+               err = CHDERR_INVALID_FILE;
+               goto cleanup;
+       }
+       return CHDERR_NONE;
+
+cleanup:
+       if (chd->map)
+               free(chd->map);
+       chd->map = NULL;
+       return err;
+}
+
+/***************************************************************************
+    INTERNAL METADATA ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+    metadata_find_entry - find a metadata entry
+-------------------------------------------------*/
+
+static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
+{
+       /* start at the beginning */
+       metaentry->offset = chd->header.metaoffset;
+       metaentry->prev = 0;
+
+       /* loop until we run out of options */
+       while (metaentry->offset != 0)
+       {
+               UINT8   raw_meta_header[METADATA_HEADER_SIZE];
+               int64_t count;
+
+               /* read the raw header */
+               filestream_seek(chd->file, metaentry->offset, SEEK_SET);
+               count = filestream_read(chd->file, raw_meta_header, sizeof(raw_meta_header));
+               if (count != sizeof(raw_meta_header))
+                       break;
+
+               /* extract the data */
+               metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]);
+               metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
+               metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
+
+               /* flags are encoded in the high byte of length */
+               metaentry->flags = metaentry->length >> 24;
+               metaentry->length &= 0x00ffffff;
+
+               /* if we got a match, proceed */
+               if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
+                       if (metaindex-- == 0)
+                               return CHDERR_NONE;
+
+               /* no match, fetch the next link */
+               metaentry->prev = metaentry->offset;
+               metaentry->offset = metaentry->next;
+       }
+
+       /* if we get here, we didn't find it */
+       return CHDERR_METADATA_NOT_FOUND;
+}
diff --git a/deps/libretro-common/formats/libchdr/libchdr_flac.c b/deps/libretro-common/formats/libchdr/libchdr_flac.c
new file mode 100644 (file)
index 0000000..e441c15
--- /dev/null
@@ -0,0 +1,324 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    flac.c
+
+    FLAC compression wrappers
+
+***************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+#include <libchdr/flac.h>
+#include <libchdr/minmax.h>
+#include <retro_miscellaneous.h>
+
+/***************************************************************************
+ *  FLAC DECODER
+ ***************************************************************************
+ */
+
+static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes);
+static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+/*-------------------------------------------------
+ *  flac_decoder - constructor
+ *-------------------------------------------------
+ */
+
+void flac_decoder_init(flac_decoder *decoder)
+{
+       decoder->decoder = FLAC__stream_decoder_new();
+       decoder->sample_rate = 0;
+       decoder->channels = 0;
+       decoder->bits_per_sample = 0;
+       decoder->compressed_offset = 0;
+       decoder->compressed_start = NULL;
+       decoder->compressed_length = 0;
+       decoder->compressed2_start = NULL;
+       decoder->compressed2_length = 0;
+       decoder->uncompressed_offset = 0;
+       decoder->uncompressed_length = 0;
+       decoder->uncompressed_swap = 0;
+}
+
+/*-------------------------------------------------
+ *  flac_decoder - destructor
+ *-------------------------------------------------
+ */
+
+void flac_decoder_free(flac_decoder* decoder)
+{
+       if ((decoder != NULL) && (decoder->decoder != NULL))
+               FLAC__stream_decoder_delete(decoder->decoder);
+}
+
+/*-------------------------------------------------
+ *  reset - reset state with the original
+ *  parameters
+ *-------------------------------------------------
+ */
+
+static int flac_decoder_internal_reset(flac_decoder* decoder)
+{
+       decoder->compressed_offset = 0;
+       if (FLAC__stream_decoder_init_stream(decoder->decoder,
+                               &flac_decoder_read_callback_static,
+                               NULL,
+                               &flac_decoder_tell_callback_static,
+                               NULL,
+                               NULL,
+                               &flac_decoder_write_callback_static,
+                               &flac_decoder_metadata_callback_static,
+                               &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return 0;
+       return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder);
+}
+
+/*-------------------------------------------------
+ *  reset - reset state with new memory parameters
+ *  and a custom-generated header
+ *-------------------------------------------------
+ */
+
+int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)
+{
+       /* modify the template header with our parameters */
+       static const uint8_t s_header_template[0x2a] =
+       {
+               0x66, 0x4C, 0x61, 0x43,                         /* +00: 'fLaC' stream header */
+               0x80,                                           /* +04: metadata block type 0 (STREAMINFO), */
+                                                               /*      flagged as last block */
+               0x00, 0x00, 0x22,                               /* +05: metadata block length = 0x22 */
+               0x00, 0x00,                                     /* +08: minimum block size */
+               0x00, 0x00,                                     /* +0A: maximum block size */
+               0x00, 0x00, 0x00,                               /* +0C: minimum frame size (0 == unknown) */
+               0x00, 0x00, 0x00,                               /* +0F: maximum frame size (0 == unknown) */
+               0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */
+                                                               /*      numchannels (2), sample bits (16), */
+                                                               /*      samples in stream (0 == unknown) */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* +2A: start of stream data */
+       };
+       memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));
+       decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8;
+       decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff;
+       decoder->custom_header[0x12] = sample_rate >> 12;
+       decoder->custom_header[0x13] = sample_rate >> 4;
+       decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
+
+       /* configure the header ahead of the provided buffer */
+       decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header);
+       decoder->compressed_length = sizeof(decoder->custom_header);
+       decoder->compressed2_start = (const FLAC__byte *)(buffer);
+       decoder->compressed2_length = length;
+       return flac_decoder_internal_reset(decoder);
+}
+
+/*-------------------------------------------------
+ *  decode_interleaved - decode to an interleaved
+ *  sound stream
+ *-------------------------------------------------
+ */
+
+int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)
+{
+       /* configure the uncompressed buffer */
+       memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));
+       decoder->uncompressed_start[0] = samples;
+       decoder->uncompressed_offset = 0;
+       decoder->uncompressed_length = num_samples;
+       decoder->uncompressed_swap = swap_endian;
+
+       /* loop until we get everything we want */
+       while (decoder->uncompressed_offset < decoder->uncompressed_length)
+               if (!FLAC__stream_decoder_process_single(decoder->decoder))
+                       return 0;
+       return 1;
+}
+
+#if 0
+/*-------------------------------------------------
+ *  decode - decode to an multiple independent
+ *  data streams
+ *-------------------------------------------------
+ */
+
+bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)
+{
+       /* make sure we don't have too many channels */
+       int chans = channels();
+       if (chans > ARRAY_SIZE(m_uncompressed_start))
+               return false;
+
+       /* configure the uncompressed buffer */
+       memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
+       for (int curchan = 0; curchan < chans; curchan++)
+               m_uncompressed_start[curchan] = samples[curchan];
+       m_uncompressed_offset = 0;
+       m_uncompressed_length = num_samples;
+       m_uncompressed_swap = swap_endian;
+
+       /* loop until we get everything we want */
+       while (m_uncompressed_offset < m_uncompressed_length)
+               if (!FLAC__stream_decoder_process_single(m_decoder))
+                       return false;
+       return true;
+}
+#endif
+
+/*-------------------------------------------------
+ *  finish - finish up the decode
+ *-------------------------------------------------
+ */
+
+uint32_t flac_decoder_finish(flac_decoder* decoder)
+{
+       /* get the final decoding position and move forward */
+       FLAC__uint64 position = 0;
+       FLAC__stream_decoder_get_decode_position(decoder->decoder, &position);
+       FLAC__stream_decoder_finish(decoder->decoder);
+
+       /* adjust position if we provided the header */
+       if (position == 0)
+               return 0;
+       if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header))
+               position -= decoder->compressed_length;
+       return (uint32_t)position;
+}
+
+/*-------------------------------------------------
+ *  read_callback - handle reads from the input
+ *  stream
+ *-------------------------------------------------
+ */
+
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       return flac_decoder_read_callback(client_data, buffer, bytes);
+}
+
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes)
+{
+       flac_decoder* decoder = (flac_decoder*)client_data;
+
+       uint32_t expected     = (uint32_t)*bytes;
+
+       /* copy from primary buffer first */
+       uint32_t outputpos    = 0;
+    
+       if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length)
+       {
+               uint32_t bytes_to_copy = (uint32_t)MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);
+               memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);
+               outputpos += bytes_to_copy;
+               decoder->compressed_offset += bytes_to_copy;
+       }
+
+       /* once we're out of that, copy from the secondary buffer */
+       if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)
+       {
+               uint32_t bytes_to_copy = (uint32_t)MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));
+               memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);
+               outputpos += bytes_to_copy;
+               decoder->compressed_offset += bytes_to_copy;
+       }
+       *bytes = outputpos;
+
+       /* return based on whether we ran out of data */
+       return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+/*-------------------------------------------------
+ *  metadata_callback - handle STREAMINFO metadata
+ *-------------------------------------------------
+ */
+
+void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+   flac_decoder *fldecoder;
+       /* ignore all but STREAMINFO metadata */
+       if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)
+               return;
+
+       /* parse out the data we care about */
+       fldecoder = (flac_decoder *)(client_data);
+       fldecoder->sample_rate = metadata->data.stream_info.sample_rate;
+       fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+       fldecoder->channels = metadata->data.stream_info.channels;
+}
+
+/*-------------------------------------------------
+ *  tell_callback - handle requests to find out
+ *  where in the input stream we are
+ *-------------------------------------------------
+ */
+
+FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset;
+       return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+/*-------------------------------------------------
+ *  write_callback - handle writes to the output
+ *  stream
+ *-------------------------------------------------
+ */
+
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       return flac_decoder_write_callback(client_data, frame, buffer);
+}
+
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       int sampnum, chan;
+   int shift, blocksize;
+       flac_decoder * decoder = (flac_decoder *)client_data;
+
+       assert(frame->header.channels == decoder->channels);
+
+       /* interleaved case */
+       shift = decoder->uncompressed_swap ? 8 : 0;
+       blocksize = frame->header.blocksize;
+       if (decoder->uncompressed_start[1] == NULL)
+       {
+               int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels;
+               for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)
+                       for (chan = 0; chan < (int)frame->header.channels; chan++)
+                               *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift));
+       }
+
+       /* non-interleaved case */
+       else
+       {
+               for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)
+                       for (chan = 0; chan < (int)frame->header.channels; chan++)
+                               if (decoder->uncompressed_start[chan] != NULL)
+                                       decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) );
+       }
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+/**
+ * @fn  void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+ *
+ * @brief   -------------------------------------------------
+ *            error_callback - handle errors (ignore them)
+ *          -------------------------------------------------.
+ *
+ * @param   decoder             The decoder.
+ * @param   status              The status.
+ * @param [in,out]  client_data If non-null, information describing the client.
+ */
+
+void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+}
diff --git a/deps/libretro-common/formats/libchdr/libchdr_flac_codec.c b/deps/libretro-common/formats/libchdr/libchdr_flac_codec.c
new file mode 100644 (file)
index 0000000..3a6e669
--- /dev/null
@@ -0,0 +1,163 @@
+/***************************************************************************
+
+    libchdr_flac_codec.c
+
+    MAME Compressed Hunks of Data file format
+
+****************************************************************************
+
+    Copyright Aaron Giles
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+        * 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 'MAME' 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 AARON GILES ''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 AARON GILES 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libchdr/chd.h>
+#include <libchdr/minmax.h>
+#include <libchdr/cdrom.h>
+#include <libchdr/flac.h>
+#include <libchdr/huffman.h>
+#include <zlib.h>
+
+#include <retro_inline.h>
+#include <streams/file_stream.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/***************************************************************************
+ *  CD FLAC DECOMPRESSOR
+ ***************************************************************************
+ */
+
+/*------------------------------------------------------
+ *  cdfl_codec_blocksize - return the optimal block size
+ *------------------------------------------------------
+ */
+
+static uint32_t cdfl_codec_blocksize(uint32_t bytes)
+{
+       /* determine FLAC block size, which must be 16-65535
+        * clamp to 2k since that's supposed to be the sweet spot */
+       uint32_t hunkbytes = bytes / 4;
+       while (hunkbytes > 2048)
+               hunkbytes /= 2;
+       return hunkbytes;
+}
+
+chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
+{
+#ifdef WANT_SUBCODE
+   chd_error ret;
+#endif
+   uint16_t native_endian = 0;
+       cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
+
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
+       if (hunkbytes % CD_FRAME_SIZE != 0)
+               return CHDERR_CODEC_ERROR;
+
+       cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
+       if (cdfl->buffer == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       /* determine whether we want native or swapped samples */
+       *(uint8_t *)(&native_endian) = 1;
+       cdfl->swap_endian = (native_endian & 1);
+
+#ifdef WANT_SUBCODE
+       /* init zlib inflater */
+       ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#endif
+
+       /* flac decoder init */
+       flac_decoder_init(&cdfl->decoder);
+       if (cdfl->decoder.decoder == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       return CHDERR_NONE;
+}
+
+void cdfl_codec_free(void *codec)
+{
+       cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
+       flac_decoder_free(&cdfl->decoder);
+#ifdef WANT_SUBCODE
+       zlib_codec_free(&cdfl->subcode_decompressor);
+#endif
+       if (cdfl->buffer)
+               free(cdfl->buffer);
+}
+
+chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       uint32_t framenum;
+   uint8_t *buffer;
+#ifdef WANT_SUBCODE
+   uint32_t offset;
+   chd_error ret;
+#endif
+       cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
+
+       /* reset and decode */
+       uint32_t frames = destlen / CD_FRAME_SIZE;
+
+       if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
+               return CHDERR_DECOMPRESSION_ERROR;
+       buffer = &cdfl->buffer[0];
+       if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
+               return CHDERR_DECOMPRESSION_ERROR;
+
+#ifdef WANT_SUBCODE
+       /* inflate the subcode data */
+       offset = flac_decoder_finish(&cdfl->decoder);
+       ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#else
+       flac_decoder_finish(&cdfl->decoder);
+#endif
+
+       /* reassemble the data */
+       for (framenum = 0; framenum < frames; framenum++)
+       {
+               memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+               memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
+#endif
+       }
+
+       return CHDERR_NONE;
+}
diff --git a/deps/libretro-common/formats/libchdr/libchdr_huffman.c b/deps/libretro-common/formats/libchdr/libchdr_huffman.c
new file mode 100644 (file)
index 0000000..d658d33
--- /dev/null
@@ -0,0 +1,563 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+****************************************************************************
+
+    huffman.c
+
+    Static Huffman compression and decompression helpers.
+
+****************************************************************************
+
+    Maximum codelength is officially (alphabetsize - 1). This would be 255 bits
+    (since we use 1 byte values). However, it is also dependent upon the number
+    of samples used, as follows:
+
+         2 bits -> 3..4 samples
+         3 bits -> 5..7 samples
+         4 bits -> 8..12 samples
+         5 bits -> 13..20 samples
+         6 bits -> 21..33 samples
+         7 bits -> 34..54 samples
+         8 bits -> 55..88 samples
+         9 bits -> 89..143 samples
+        10 bits -> 144..232 samples
+        11 bits -> 233..376 samples
+        12 bits -> 377..609 samples
+        13 bits -> 610..986 samples
+        14 bits -> 987..1596 samples
+        15 bits -> 1597..2583 samples
+        16 bits -> 2584..4180 samples   -> note that a 4k data size guarantees codelength <= 16 bits
+        17 bits -> 4181..6764 samples
+        18 bits -> 6765..10945 samples
+        19 bits -> 10946..17710 samples
+        20 bits -> 17711..28656 samples
+        21 bits -> 28657..46367 samples
+        22 bits -> 46368..75024 samples
+        23 bits -> 75025..121392 samples
+        24 bits -> 121393..196417 samples
+        25 bits -> 196418..317810 samples
+        26 bits -> 317811..514228 samples
+        27 bits -> 514229..832039 samples
+        28 bits -> 832040..1346268 samples
+        29 bits -> 1346269..2178308 samples
+        30 bits -> 2178309..3524577 samples
+        31 bits -> 3524578..5702886 samples
+        32 bits -> 5702887..9227464 samples
+
+    Looking at it differently, here is where powers of 2 fall into these buckets:
+
+          256 samples -> 11 bits max
+          512 samples -> 12 bits max
+           1k samples -> 14 bits max
+           2k samples -> 15 bits max
+           4k samples -> 16 bits max
+           8k samples -> 18 bits max
+          16k samples -> 19 bits max
+          32k samples -> 21 bits max
+          64k samples -> 22 bits max
+         128k samples -> 24 bits max
+         256k samples -> 25 bits max
+         512k samples -> 27 bits max
+           1M samples -> 28 bits max
+           2M samples -> 29 bits max
+           4M samples -> 31 bits max
+           8M samples -> 32 bits max
+
+****************************************************************************
+
+    Delta-RLE encoding works as follows:
+
+    Starting value is assumed to be 0. All data is encoded as a delta
+    from the previous value, such that final[i] = final[i - 1] + delta.
+    Long runs of 0s are RLE-encoded as follows:
+
+        0x100 = repeat count of 8
+        0x101 = repeat count of 9
+        0x102 = repeat count of 10
+        0x103 = repeat count of 11
+        0x104 = repeat count of 12
+        0x105 = repeat count of 13
+        0x106 = repeat count of 14
+        0x107 = repeat count of 15
+        0x108 = repeat count of 16
+        0x109 = repeat count of 32
+        0x10a = repeat count of 64
+        0x10b = repeat count of 128
+        0x10c = repeat count of 256
+        0x10d = repeat count of 512
+        0x10e = repeat count of 1024
+        0x10f = repeat count of 2048
+
+    Note that repeat counts are reset at the end of a row, so if a 0 run
+    extends to the end of a row, a large repeat count may be used.
+
+    The reason for starting the run counts at 8 is that 0 is expected to
+    be the most common symbol, and is typically encoded in 1 or 2 bits.
+
+***************************************************************************/
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libchdr/huffman.h>
+#include <libchdr/minmax.h>
+
+/***************************************************************************
+ *  MACROS
+ ***************************************************************************
+ */
+
+#define MAKE_LOOKUP(code,bits)  (((code) << 5) | ((bits) & 0x1f))
+
+/***************************************************************************
+ *  IMPLEMENTATION
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  huffman_context_base - create an encoding/
+ *  decoding context
+ *-------------------------------------------------
+ */
+
+struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
+{
+   struct huffman_decoder* decoder;
+       /* limit to 24 bits */
+       if (maxbits > 24)
+               return NULL;
+
+       decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));
+       decoder->numcodes = numcodes;
+       decoder->maxbits = maxbits;
+       decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));
+       decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);
+       decoder->datahisto = NULL;
+       decoder->prevdata = 0;
+       decoder->rleremaining = 0;
+       return decoder;
+}
+
+void delete_huffman_decoder(struct huffman_decoder* decoder)
+{
+       if (decoder != NULL)
+       {
+               if (decoder->lookup != NULL)
+                       free(decoder->lookup);
+               if (decoder->huffnode != NULL)
+                       free(decoder->huffnode);
+               free(decoder);
+       }
+}
+
+/*-------------------------------------------------
+ *  decode_one - decode a single code from the
+ *  huffman stream
+ *-------------------------------------------------
+ */
+
+uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       /* peek ahead to get maxbits worth of data */
+       uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);
+
+       /* look it up, then remove the actual number of bits for this code */
+       lookup_value lookup = decoder->lookup[bits];
+       bitstream_remove(bitbuf, lookup & 0x1f);
+
+       /* return the value */
+       return lookup >> 5;
+}
+
+/*-------------------------------------------------
+ *  import_tree_rle - import an RLE-encoded
+ *  huffman tree from a source data stream
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+   enum huffman_error error;
+       /* bits per entry depends on the maxbits */
+       int numbits;
+       int curnode;
+       if (decoder->maxbits >= 16)
+               numbits = 5;
+       else if (decoder->maxbits >= 8)
+               numbits = 4;
+       else
+               numbits = 3;
+
+       /* loop until we read all the nodes */
+       for (curnode = 0; curnode < (int)decoder->numcodes; /* blank */)
+       {
+               /* a non-one value is just raw */
+               int nodebits = bitstream_read(bitbuf, numbits);
+               if (nodebits != 1)
+                       decoder->huffnode[curnode++].numbits = nodebits;
+
+               /* a one value is an escape code */
+               else
+               {
+                       /* a double 1 is just a single 1 */
+                       nodebits = bitstream_read(bitbuf, numbits);
+                       if (nodebits == 1)
+                               decoder->huffnode[curnode++].numbits = nodebits;
+
+                       /* otherwise, we need one for value for the repeat count */
+                       else
+                       {
+                               int repcount = bitstream_read(bitbuf, numbits) + 3;
+                               while (repcount--)
+                                       decoder->huffnode[curnode++].numbits = nodebits;
+                       }
+               }
+       }
+
+       /* make sure we ended up with the right number */
+       if (curnode != (int)decoder->numcodes)
+               return HUFFERR_INVALID_DATA;
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       error = huffman_assign_canonical_codes(decoder);
+       if (error != HUFFERR_NONE)
+               return error;
+
+       /* build the lookup table */
+       huffman_build_lookup_table(decoder);
+
+       /* determine final input length and report errors */
+       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  import_tree_huffman - import a huffman-encoded
+ *  huffman tree from a source data stream
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       int last = 0;
+       int curcode;
+   uint32_t temp;
+   enum huffman_error error;
+       uint8_t rlefullbits = 0;
+       int index, count = 0;
+   int start;
+       /* start by parsing the lengths for the small tree */
+       struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
+
+       smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
+       start = bitstream_read(bitbuf, 3) + 1;
+
+       for (index = 1; index < 24; index++)
+       {
+               if (index < start || count == 7)
+                       smallhuff->huffnode[index].numbits = 0;
+               else
+               {
+                       count = bitstream_read(bitbuf, 3);
+                       smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count;
+               }
+       }
+
+       /* then regenerate the tree */
+       error = huffman_assign_canonical_codes(smallhuff);
+       if (error != HUFFERR_NONE)
+               return error;
+       huffman_build_lookup_table(smallhuff);
+
+       /* determine the maximum length of an RLE count */
+       temp = decoder->numcodes - 9;
+       while (temp != 0)
+    {
+        temp >>= 1;
+        rlefullbits++;
+    }
+
+       /* now process the rest of the data */
+       for (curcode = 0; curcode < (int)decoder->numcodes; /* blank */)
+       {
+               int value = huffman_decode_one(smallhuff, bitbuf);
+               if (value != 0)
+                       decoder->huffnode[curcode++].numbits = last = value - 1;
+               else
+               {
+                       int count = bitstream_read(bitbuf, 3) + 2;
+                       if (count == 7+2)
+                               count += bitstream_read(bitbuf, rlefullbits);
+                       for (/* blank */; count != 0 && curcode < (int)decoder->numcodes; count--)
+                               decoder->huffnode[curcode++].numbits = last;
+               }
+       }
+
+       /* make sure we ended up with the right number */
+       if (curcode != (int)decoder->numcodes)
+   {
+      delete_huffman_decoder(smallhuff);
+               return HUFFERR_INVALID_DATA;
+   }
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       error = huffman_assign_canonical_codes(decoder);
+       if (error != HUFFERR_NONE)
+   {
+      delete_huffman_decoder(smallhuff);
+               return error;
+   }
+
+       /* build the lookup table */
+       huffman_build_lookup_table(decoder);
+       delete_huffman_decoder(smallhuff);
+
+       /* determine final input length and report errors */
+       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  compute_tree_from_histo - common backend for
+ *  computing a tree based on the data histogram
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
+{
+       /* compute the number of data items in the histogram */
+       int i;
+   uint32_t upperweight;
+       uint32_t lowerweight = 0;
+       uint32_t sdatacount = 0;
+       for (i = 0; i < (int)decoder->numcodes; i++)
+               sdatacount += decoder->datahisto[i];
+
+       /* binary search to achieve the optimum encoding */
+       upperweight = sdatacount * 2;
+
+   for (;;)
+       {
+               /* build a tree using the current weight */
+               uint32_t curweight = (upperweight + lowerweight) / 2;
+               int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);
+
+               /* apply binary search here */
+               if (curmaxbits <= decoder->maxbits)
+               {
+                       lowerweight = curweight;
+
+                       /* early out if it worked with the raw weights, or if we're done searching */
+                       if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
+                               break;
+               }
+               else
+                       upperweight = curweight;
+       }
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       return huffman_assign_canonical_codes(decoder);
+}
+
+/***************************************************************************
+ *  INTERNAL FUNCTIONS
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  tree_node_compare - compare two tree nodes
+ *  by weight
+ *-------------------------------------------------
+ */
+
+static int huffman_tree_node_compare(const void *item1, const void *item2)
+{
+       const struct node_t *node1 = *(const struct node_t **)item1;
+       const struct node_t *node2 = *(const struct node_t **)item2;
+       if (node2->weight != node1->weight)
+               return node2->weight - node1->weight;
+       if (node2->bits - node1->bits == 0)
+               fprintf(stderr, "identical node sort keys, should not happen!\n");
+       return (int)node1->bits - (int)node2->bits;
+}
+
+/*-------------------------------------------------
+ *  build_tree - build a huffman tree based on the
+ *  data distribution
+ *-------------------------------------------------
+ */
+
+int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
+{
+   int nextalloc;
+       int maxbits = 0;
+       /* make a list of all non-zero nodes */
+       struct node_t** list   = (struct node_t**)
+      malloc(sizeof(struct node_t*) * decoder->numcodes * 2);
+       int curcode, listitems = 0;
+
+       memset(decoder->huffnode, 0,
+         decoder->numcodes * sizeof(decoder->huffnode[0]));
+
+       for (curcode = 0; curcode < (int)decoder->numcodes; curcode++)
+               if (decoder->datahisto[curcode] != 0)
+               {
+                       list[listitems++] = &decoder->huffnode[curcode];
+                       decoder->huffnode[curcode].count = decoder->datahisto[curcode];
+                       decoder->huffnode[curcode].bits = curcode;
+
+                       /* scale the weight by the current effective length, ensuring we don't go to 0 */
+                       decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
+                       if (decoder->huffnode[curcode].weight == 0)
+                               decoder->huffnode[curcode].weight = 1;
+               }
+
+#if 0
+   {
+      unsigned i;
+      fprintf(stderr, "Pre-sort:\n");
+      for (i = 0; i < listitems; i++)
+         fprintf(stderr, "weight: %d code: %d\n",
+               list[i]->m_weight, list[i]->m_bits);
+   }
+#endif
+
+       /* sort the list by weight, largest weight first */
+       qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);
+
+#if 0
+   fprintf(stderr, "Post-sort:\n");
+   for (int i = 0; i < listitems; i++) {
+      fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
+   }
+   fprintf(stderr, "===================\n");
+#endif
+
+       /* now build the tree */
+       nextalloc = decoder->numcodes;
+
+       while (listitems > 1)
+       {
+               int curitem;
+               /* remove lowest two items */
+               struct node_t* node1   = &(*list[--listitems]);
+               struct node_t* node0   = &(*list[--listitems]);
+
+               /* create new node */
+               struct node_t* newnode = &decoder->huffnode[nextalloc++];
+               newnode->parent        = NULL;
+               node0->parent          =
+         node1->parent       = newnode;
+               newnode->weight        =
+         node0->weight + node1->weight;
+
+               /* insert into list at appropriate location */
+               for (curitem = 0; curitem < listitems; curitem++)
+                       if (newnode->weight > list[curitem]->weight)
+                       {
+                               memmove(&list[curitem+1],
+                  &list[curitem],
+                  (listitems - curitem) * sizeof(list[0]));
+                               break;
+                       }
+               list[curitem] = newnode;
+               listitems++;
+       }
+
+       /* compute the number of bits in each code,
+    * and fill in another histogram */
+       for (curcode = 0; curcode < (int)decoder->numcodes; curcode++)
+       {
+               struct node_t *curnode;
+               struct node_t* node = &decoder->huffnode[curcode];
+               node->numbits = 0;
+               node->bits = 0;
+
+               /* if we have a non-zero weight, compute the number of bits */
+               if (node->weight > 0)
+               {
+                       /* determine the number of bits for this node */
+                       for (curnode = node;
+               curnode->parent != NULL; curnode = curnode->parent)
+                               node->numbits++;
+                       if (node->numbits == 0)
+                               node->numbits = 1;
+
+                       /* keep track of the max */
+                       maxbits = MAX(maxbits, ((int)node->numbits));
+               }
+       }
+   free(list);
+       return maxbits;
+}
+
+/*-------------------------------------------------
+ *  assign_canonical_codes - assign canonical codes
+ *  to all the nodes based on the number of bits
+ *  in each
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
+{
+       uint32_t curstart = 0;
+       /* build up a histogram of bit lengths */
+       int curcode, codelen;
+       uint32_t bithisto[33] = { 0 };
+       for (curcode = 0; curcode < (int)decoder->numcodes; curcode++)
+       {
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > decoder->maxbits)
+                       return HUFFERR_INTERNAL_INCONSISTENCY;
+               if (node->numbits <= 32)
+                       bithisto[node->numbits]++;
+       }
+
+       /* for each code length, determine the starting code number */
+       for (codelen = 32; codelen > 0; codelen--)
+       {
+               uint32_t nextstart = (curstart + bithisto[codelen]) >> 1;
+               if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))
+                       return HUFFERR_INTERNAL_INCONSISTENCY;
+               bithisto[codelen] = curstart;
+               curstart = nextstart;
+       }
+
+       /* now assign canonical codes */
+       for (curcode = 0; curcode < (int)decoder->numcodes; curcode++)
+       {
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > 0)
+                       node->bits = bithisto[node->numbits]++;
+       }
+       return HUFFERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  build_lookup_table - build a lookup table for
+ *  fast decoding
+ *-------------------------------------------------
+ */
+
+void huffman_build_lookup_table(struct huffman_decoder* decoder)
+{
+       /* iterate over all codes */
+       int curcode;
+       for (curcode = 0; curcode < (int)decoder->numcodes; curcode++)
+       {
+               /* process all nodes which have non-zero bits */
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > 0)
+               {
+                       /* set up the entry */
+                       lookup_value value = MAKE_LOOKUP(curcode, node->numbits);
+
+                       /* fill all matching entries */
+                       int shift          = decoder->maxbits - node->numbits;
+                       lookup_value *dest = &decoder->lookup[node->bits << shift];
+                       lookup_value *destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
+                       while (dest <= destend)
+                               *dest++ = value;
+               }
+       }
+}
diff --git a/deps/libretro-common/formats/libchdr/libchdr_lzma.c b/deps/libretro-common/formats/libchdr/libchdr_lzma.c
new file mode 100644 (file)
index 0000000..660a2f2
--- /dev/null
@@ -0,0 +1,366 @@
+/***************************************************************************
+
+    libchdr_lzma_codec.c
+
+    MAME Compressed Hunks of Data file format
+
+****************************************************************************
+
+    Copyright Aaron Giles
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+        * 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 'MAME' 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 AARON GILES ''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 AARON GILES 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+#include <libchdr/chd.h>
+#include <libchdr/minmax.h>
+#include <libchdr/cdrom.h>
+#include <libchdr/lzma.h>
+#include <libchdr/huffman.h>
+
+#include <retro_inline.h>
+#include <streams/file_stream.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/***************************************************************************
+ *  LZMA ALLOCATOR HELPER
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  lzma_fast_alloc - fast malloc for lzma, which
+ *  allocates and frees memory frequently
+ *-------------------------------------------------
+ */
+
+/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
+#define LZMA_MIN_ALIGNMENT_BITS 512
+#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
+
+static void *lzma_fast_alloc(void *p, size_t size)
+{
+       int scan;
+       uint32_t *addr        = NULL;
+       lzma_allocator *codec = (lzma_allocator *)(p);
+       uintptr_t vaddr = 0;
+
+       /* compute the size, rounding to the nearest 1k */
+       size = (size + 0x3ff) & ~0x3ff;
+
+       /* reuse a hunk if we can */
+       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       {
+               uint32_t *ptr = codec->allocptr[scan];
+               if (ptr != NULL && size == *ptr)
+               {
+                       /* set the low bit of the size so we don't match next time */
+                       *ptr |= 1;
+
+                       /* return aligned address of the block */
+                       return codec->allocptr2[scan];
+               }
+       }
+
+       /* alloc a new one and put it into the list */
+       addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
+       if (addr==NULL)
+               return NULL;
+       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       {
+               if (codec->allocptr[scan] == NULL)
+               {
+                       /* store block address */
+                       codec->allocptr[scan] = addr;
+
+                       /* compute aligned address, store it */
+                       vaddr = (uintptr_t)addr;
+                       vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
+                       codec->allocptr2[scan] = (uint32_t*)vaddr;
+                       break;
+               }
+       }
+
+       /* set the low bit of the size so we don't match next time */
+       *addr = size | 1;
+
+       /* return aligned address */
+       return (void*)vaddr;
+}
+
+/*-------------------------------------------------
+ *  lzma_fast_free - fast free for lzma, which
+ *  allocates and frees memory frequently
+ *-------------------------------------------------
+ */
+static void lzma_fast_free(void *p, void *address)
+{
+       int scan;
+       uint32_t *ptr = NULL;
+       lzma_allocator *codec = NULL;
+
+       if (address == NULL)
+               return;
+
+       codec = (lzma_allocator *)(p);
+
+       /* find the hunk */
+       ptr = (uint32_t *)address;
+       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       {
+               if (ptr == codec->allocptr2[scan])
+               {
+                       /* clear the low bit of the size to allow matches */
+                       *codec->allocptr[scan] &= ~1;
+                       return;
+               }
+       }
+}
+
+/*-------------------------------------------------
+ *  lzma_allocator_init
+ *-------------------------------------------------
+ */
+
+void lzma_allocator_init(void* p)
+{
+       lzma_allocator *codec = (lzma_allocator *)(p);
+
+       /* reset pointer list */
+       memset(codec->allocptr, 0, sizeof(codec->allocptr));
+       codec->Alloc = lzma_fast_alloc;
+       codec->Free = lzma_fast_free;
+}
+
+/*-------------------------------------------------
+ *  lzma_allocator_free
+ *-------------------------------------------------
+ */
+
+void lzma_allocator_free(void* p )
+{
+       lzma_allocator *codec = (lzma_allocator *)(p);
+
+       /* free our memory */
+       int i;
+       for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
+       {
+               if (codec->allocptr[i] != NULL)
+                       free(codec->allocptr[i]);
+       }
+}
+
+/***************************************************************************
+ *  LZMA DECOMPRESSOR
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  lzma_codec_init - constructor
+ *-------------------------------------------------
+ */
+
+chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
+{
+       CLzmaEncProps encoder_props;
+   CLzmaEncHandle enc;
+       uint8_t decoder_props[LZMA_PROPS_SIZE];
+   lzma_allocator* alloc;
+   size_t props_size;
+       lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
+
+       /* construct the decoder */
+       LzmaDec_Construct(&lzma_codec->decoder);
+
+       /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
+        * This code assumes that the current version of the encoder imposes the same requirements on the
+        * decoder as the encoder used to produce the file.  This is not necessarily true.  The format
+        * needs to be changed so the encoder properties are written to the file.
+
+        * configure the properties like the compressor did */
+       LzmaEncProps_Init(&encoder_props);
+       encoder_props.level = 9;
+       encoder_props.reduceSize = hunkbytes;
+       LzmaEncProps_Normalize(&encoder_props);
+
+       /* convert to decoder properties */
+       alloc = &lzma_codec->allocator;
+       lzma_allocator_init(alloc);
+       enc = LzmaEnc_Create((ISzAlloc*)alloc);
+       if (!enc)
+               return CHDERR_DECOMPRESSION_ERROR;
+       if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
+       {
+               LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
+               return CHDERR_DECOMPRESSION_ERROR;
+       }
+       props_size = sizeof(decoder_props);
+       if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
+       {
+               LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
+               return CHDERR_DECOMPRESSION_ERROR;
+       }
+       LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
+
+       /* do memory allocations */
+       if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       /* Okay */
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  lzma_codec_free
+ *-------------------------------------------------
+ */
+
+void lzma_codec_free(void* codec)
+{
+       lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
+       lzma_allocator* alloc = &lzma_codec->allocator;
+
+       /* free memory */
+       LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);
+       lzma_allocator_free(alloc);
+}
+
+/*-------------------------------------------------
+ *  decompress - decompress data using the LZMA
+ *  codec
+ *-------------------------------------------------
+ */
+
+chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       ELzmaStatus status;
+   SRes res;
+   size_t consumedlen, decodedlen;
+       /* initialize */
+       lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
+       LzmaDec_Init(&lzma_codec->decoder);
+
+       /* decode */
+       consumedlen = complen;
+       decodedlen = destlen;
+       res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
+       if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
+               return CHDERR_DECOMPRESSION_ERROR;
+       return CHDERR_NONE;
+}
+
+/* cdlz */
+chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
+{
+       chd_error ret;
+       cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
+
+       /* allocate buffer */
+       cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
+       if (cdlz->buffer == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       ret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+
+#ifdef WANT_SUBCODE
+       ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#endif
+
+       return CHDERR_NONE;
+}
+
+void cdlz_codec_free(void* codec)
+{
+       cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
+
+       lzma_codec_free(&cdlz->base_decompressor);
+#ifdef WANT_SUBCODE
+       zlib_codec_free(&cdlz->subcode_decompressor);
+#endif
+       if (cdlz->buffer)
+               free(cdlz->buffer);
+}
+
+chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+#ifdef WANT_RAW_DATA_SECTOR
+       uint8_t *sector;
+#endif
+       uint32_t framenum;
+       cdlz_codec_data* cdlz = (cdlz_codec_data*)codec;
+
+       /* determine header bytes */
+       uint32_t frames = destlen / CD_FRAME_SIZE;
+       uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
+       uint32_t ecc_bytes = (frames + 7) / 8;
+       uint32_t header_bytes = ecc_bytes + complen_bytes;
+
+       /* extract compressed length of base */
+       uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
+       if (complen_bytes > 2)
+               complen_base = (complen_base << 8) | src[ecc_bytes + 2];
+
+       /* reset and decode */
+       lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+       if (header_bytes + complen_base >= complen)
+               return CHDERR_DECOMPRESSION_ERROR;
+       zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
+#endif
+
+       /* reassemble the data */
+       for (framenum = 0; framenum < frames; framenum++)
+       {
+               memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+               memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
+#endif
+
+#ifdef WANT_RAW_DATA_SECTOR
+               /* reconstitute the ECC data and sync header */
+               sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
+               if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
+               {
+                       memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
+                       ecc_generate(sector);
+               }
+#endif
+       }
+       return CHDERR_NONE;
+}
diff --git a/deps/libretro-common/formats/libchdr/libchdr_zlib.c b/deps/libretro-common/formats/libchdr/libchdr_zlib.c
new file mode 100644 (file)
index 0000000..e02ab31
--- /dev/null
@@ -0,0 +1,313 @@
+/***************************************************************************
+
+    libchdr_zlib.c
+
+    MAME Compressed Hunks of Data file format
+
+****************************************************************************
+
+    Copyright Aaron Giles
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+        * 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 'MAME' 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 AARON GILES ''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 AARON GILES 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libchdr/chd.h>
+#include <libchdr/minmax.h>
+#include <libchdr/cdrom.h>
+#include <libchdr/huffman.h>
+#include <libchdr/libchdr_zlib.h>
+#include <zlib.h>
+
+#include <retro_inline.h>
+#include <streams/file_stream.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* cdzl */
+
+chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
+{
+       chd_error ret;
+       cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
+
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
+       if (hunkbytes % CD_FRAME_SIZE != 0)
+               return CHDERR_CODEC_ERROR;
+
+       cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
+       if (cdzl->buffer == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       ret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+
+#ifdef WANT_SUBCODE
+       ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#endif
+
+       return CHDERR_NONE;
+}
+
+void cdzl_codec_free(void *codec)
+{
+       cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
+
+       zlib_codec_free(&cdzl->base_decompressor);
+#ifdef WANT_SUBCODE
+       zlib_codec_free(&cdzl->subcode_decompressor);
+#endif
+       if (cdzl->buffer)
+               free(cdzl->buffer);
+}
+
+chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+#ifdef WANT_RAW_DATA_SECTOR
+       uint8_t *sector;
+#endif
+       uint32_t framenum;
+       cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
+
+       /* determine header bytes */
+       uint32_t frames = destlen / CD_FRAME_SIZE;
+       uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
+       uint32_t ecc_bytes = (frames + 7) / 8;
+       uint32_t header_bytes = ecc_bytes + complen_bytes;
+
+       /* extract compressed length of base */
+       uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
+       if (complen_bytes > 2)
+               complen_base = (complen_base << 8) | src[ecc_bytes + 2];
+
+       /* reset and decode */
+       zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+       zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
+#endif
+
+       /* reassemble the data */
+       for (framenum = 0; framenum < frames; framenum++)
+       {
+               memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+               memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
+#endif
+
+#ifdef WANT_RAW_DATA_SECTOR
+               /* reconstitute the ECC data and sync header */
+               sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
+               if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
+               {
+                       memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
+                       ecc_generate(sector);
+               }
+#endif
+       }
+       return CHDERR_NONE;
+}
+
+/***************************************************************************
+    ZLIB COMPRESSION CODEC
+***************************************************************************/
+
+/*-------------------------------------------------
+    zlib_codec_init - initialize the ZLIB codec
+-------------------------------------------------*/
+
+chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
+{
+       int zerr;
+       chd_error err;
+       zlib_codec_data *data = (zlib_codec_data*)codec;
+
+       /* clear the buffers */
+       memset(data, 0, sizeof(zlib_codec_data));
+
+       /* init the inflater first */
+       data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */
+       data->inflater.avail_in = 0;
+       data->inflater.zalloc = zlib_fast_alloc;
+       data->inflater.zfree = zlib_fast_free;
+       data->inflater.opaque = &data->allocator;
+       zerr = inflateInit2(&data->inflater, -MAX_WBITS);
+
+       /* convert errors */
+       if (zerr == Z_MEM_ERROR)
+               err = CHDERR_OUT_OF_MEMORY;
+       else if (zerr != Z_OK)
+               err = CHDERR_CODEC_ERROR;
+       else
+               err = CHDERR_NONE;
+
+       /* handle an error */
+       if (err != CHDERR_NONE)
+               zlib_codec_free(data);
+
+       return err;
+}
+
+/*-------------------------------------------------
+    zlib_codec_free - free data for the ZLIB
+    codec
+-------------------------------------------------*/
+
+void zlib_codec_free(void *codec)
+{
+       zlib_codec_data *data = (zlib_codec_data *)codec;
+
+       /* deinit the streams */
+       if (data != NULL)
+       {
+               int i;
+               zlib_allocator alloc;
+
+               inflateEnd(&data->inflater);
+
+               /* free our fast memory */
+               alloc = data->allocator;
+               for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+                       if (alloc.allocptr[i])
+                               free(alloc.allocptr[i]);
+       }
+}
+
+/*-------------------------------------------------
+    zlib_codec_decompress - decomrpess data using
+    the ZLIB codec
+-------------------------------------------------*/
+
+chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       zlib_codec_data *data = (zlib_codec_data *)codec;
+       int zerr;
+
+       /* reset the decompressor */
+       data->inflater.next_in = (Bytef *)src;
+       data->inflater.avail_in = complen;
+       data->inflater.total_in = 0;
+       data->inflater.next_out = (Bytef *)dest;
+       data->inflater.avail_out = destlen;
+       data->inflater.total_out = 0;
+       zerr = inflateReset(&data->inflater);
+       if (zerr != Z_OK)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       /* do it */
+       zerr = inflate(&data->inflater, Z_FINISH);
+       (void)zerr;
+       if (data->inflater.total_out != destlen)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    zlib_fast_alloc - fast malloc for ZLIB, which
+    allocates and frees memory frequently
+-------------------------------------------------*/
+
+/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
+#define ZLIB_MIN_ALIGNMENT_BITS 512
+#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
+
+voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
+{
+       zlib_allocator *alloc = (zlib_allocator *)opaque;
+       uintptr_t paddr = 0;
+       UINT32 *ptr;
+       int i;
+
+       /* compute the size, rounding to the nearest 1k */
+       size = (size * items + 0x3ff) & ~0x3ff;
+
+       /* reuse a hunk if we can */
+       for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+       {
+               ptr = alloc->allocptr[i];
+               if (ptr && size == *ptr)
+               {
+                       /* set the low bit of the size so we don't match next time */
+                       *ptr |= 1;
+
+                       /* return aligned block address */
+                       return (voidpf)(alloc->allocptr2[i]);
+               }
+       }
+
+       /* alloc a new one */
+       ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
+       if (!ptr)
+               return NULL;
+
+       /* put it into the list */
+       for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+               if (!alloc->allocptr[i])
+               {
+                       alloc->allocptr[i] = ptr;
+                       paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
+                       alloc->allocptr2[i] = (uint32_t*)paddr;
+                       break;
+               }
+
+       /* set the low bit of the size so we don't match next time */
+       *ptr = size | 1;
+
+       /* return aligned block address */
+       return (voidpf)paddr;
+}
+
+/*-------------------------------------------------
+    zlib_fast_free - fast free for ZLIB, which
+    allocates and frees memory frequently
+-------------------------------------------------*/
+
+void zlib_fast_free(voidpf opaque, voidpf address)
+{
+       zlib_allocator *alloc = (zlib_allocator *)opaque;
+       UINT32 *ptr = (UINT32 *)address;
+       int i;
+
+       /* find the hunk */
+       for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+               if (ptr == alloc->allocptr2[i])
+               {
+                       /* clear the low bit of the size to allow matches */
+                       *(alloc->allocptr[i]) &= ~1;
+                       return;
+               }
+}
diff --git a/deps/libretro-common/formats/logiqx_dat/logiqx_dat.c b/deps/libretro-common/formats/logiqx_dat/logiqx_dat.c
new file mode 100644 (file)
index 0000000..bd02c52
--- /dev/null
@@ -0,0 +1,457 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (logiqx_dat.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <file/file_path.h>
+#include <string/stdstring.h>
+#include <formats/rxml.h>
+
+#include <formats/logiqx_dat.h>
+
+/* Holds all internal DAT file data */
+struct logiqx_dat
+{
+   rxml_document_t *data;
+   rxml_node_t *current_node;
+};
+
+/* List of HTML formatting codes that must
+ * be replaced when parsing XML data */
+const char *logiqx_dat_html_code_list[][2] = { 
+   {"&amp;",  "&"},
+   {"&apos;", "'"},
+   {"&gt;",   ">"}, 
+   {"&lt;",   "<"},
+   {"&quot;", "\""} 
+};
+
+#define LOGIQX_DAT_HTML_CODE_LIST_SIZE 5
+
+/* Validation */
+
+/* Performs rudimentary validation of the specified
+ * Logiqx XML DAT file path (not rigorous - just
+ * enough to prevent obvious errors).
+ * Also provides access to file size (DAT files can
+ * be very large, so it is useful to have this information
+ * on hand - i.e. so we can check that the system has
+ * enough free memory to load the file). */ 
+bool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size)
+{
+   const char *file_ext = NULL;
+   int32_t file_size_int;
+
+   if (string_is_empty(path))
+      return false;
+
+   /* Check file extension */
+   file_ext = path_get_extension(path);
+
+   if (string_is_empty(file_ext))
+      return false;
+
+   if (!string_is_equal_noncase(file_ext, "dat") &&
+       !string_is_equal_noncase(file_ext, "xml"))
+      return false;
+
+   /* Ensure file exists */
+   if (!path_is_valid(path))
+      return false;
+
+   /* Get file size */
+   file_size_int = path_get_size(path);
+
+   if (file_size_int <= 0)
+      return false;
+
+   if (file_size)
+      *file_size = (uint64_t)file_size_int;
+
+   return true;
+}
+
+/* File initialisation/de-initialisation */
+
+/* Loads specified Logiqx XML DAT file from disk.
+ * Returned logiqx_dat_t object must be free'd using
+ * logiqx_dat_free().
+ * Returns NULL if file is invalid or a read error
+ * occurs. */
+logiqx_dat_t *logiqx_dat_init(const char *path)
+{
+   logiqx_dat_t *dat_file = NULL;
+   rxml_node_t *root_node = NULL;
+
+   /* Check file path */
+   if (!logiqx_dat_path_is_valid(path, NULL))
+      goto error;
+
+   /* Create logiqx_dat_t object */
+   dat_file = (logiqx_dat_t*)calloc(1, sizeof(*dat_file));
+
+   if (!dat_file)
+      goto error;
+
+   /* Read file from disk */
+   dat_file->data = rxml_load_document(path);
+
+   if (!dat_file->data)
+      goto error;
+
+   /* Ensure root node has the correct name */
+   root_node = rxml_root_node(dat_file->data);
+
+   if (!root_node)
+      goto error;
+
+   if (string_is_empty(root_node->name))
+      goto error;
+
+   /* > Logiqx XML uses:           'datafile'
+    * > MAME List XML uses:        'mame'
+    * > MAME 'Software List' uses: 'softwarelist' */
+   if (!string_is_equal(root_node->name, "datafile") &&
+       !string_is_equal(root_node->name, "mame") &&
+       !string_is_equal(root_node->name, "softwarelist"))
+      goto error;
+
+   /* Get pointer to initial child node */
+   dat_file->current_node = root_node->children;
+
+   if (!dat_file->current_node)
+      goto error;
+
+   /* All is well - return logiqx_dat_t object */
+   return dat_file;
+
+error:
+   logiqx_dat_free(dat_file);
+   return NULL;
+}
+
+/* Frees specified DAT file */
+void logiqx_dat_free(logiqx_dat_t *dat_file)
+{
+   if (!dat_file)
+      return;
+
+   dat_file->current_node = NULL;
+
+   if (dat_file->data)
+   {
+      rxml_free_document(dat_file->data);
+      dat_file->data = NULL;
+   }
+
+   free(dat_file);
+   dat_file = NULL;
+}
+
+/* Game information access */
+
+/* Returns true if specified node is a 'game' entry */
+static bool logiqx_dat_is_game_node(rxml_node_t *node)
+{
+   const char *node_name = NULL;
+
+   if (!node)
+      return false;
+
+   /* Check node name */
+   node_name = node->name;
+
+   if (string_is_empty(node_name))
+      return false;
+
+   /* > Logiqx XML uses:           'game'
+    * > MAME List XML uses:        'machine'
+    * > MAME 'Software List' uses: 'software' */
+   return string_is_equal(node_name, "game") ||
+          string_is_equal(node_name, "machine") ||
+          string_is_equal(node_name, "software");
+}
+
+/* Returns true if specified node is a game
+ * node containing information for a game with
+ * the specified name */
+static bool logiqx_dat_game_node_matches_name(
+      rxml_node_t *node, const char *game_name)
+{
+   const char *node_game_name = NULL;
+
+   if (!logiqx_dat_is_game_node(node) ||
+       string_is_empty(game_name))
+      return false;
+
+   /* Get 'name' attribute of XML node */
+   node_game_name = rxml_node_attrib(node, "name");
+
+   if (string_is_empty(node_game_name))
+      return false;
+
+   return string_is_equal(node_game_name, game_name);
+}
+
+/* The XML element data strings returned from
+ * DAT files are very 'messy'. This function
+ * removes all cruft, replaces formatting strings
+ * and copies the result (if valid) to 'str' */
+static void logiqx_dat_sanitise_element_data(
+      const char *data, char *str, size_t len)
+{
+   char sanitised_data[PATH_MAX_LENGTH];
+   size_t i;
+
+   sanitised_data[0] = '\0';
+
+   if (string_is_empty(data))
+      return;
+
+   strlcpy(sanitised_data, data, sizeof(sanitised_data));
+
+   /* Element data includes leading/trailing
+    * newline characters - trim them away */
+   string_trim_whitespace(sanitised_data);
+
+   if (string_is_empty(sanitised_data))
+      return;
+
+   /* XML has a number of special characters that
+    * are handled using a HTML formatting codes.
+    * All of these have to be replaced...
+    * &amp;  -> &
+    * &apos; -> '
+    * &gt;   -> >
+    * &lt;   -> <
+    * &quot; -> "
+    */
+   for (i = 0; i < LOGIQX_DAT_HTML_CODE_LIST_SIZE; i++)
+   {
+      const char *find_string    = logiqx_dat_html_code_list[i][0];
+      const char *replace_string = logiqx_dat_html_code_list[i][1];
+
+      /* string_replace_substring() is expensive
+       * > only invoke if element string contains
+       *   HTML code */
+      if (strstr(sanitised_data, find_string))
+      {
+         char *tmp = string_replace_substring(
+               sanitised_data,
+               find_string,    strlen(find_string),
+               replace_string, strlen(replace_string));
+
+         if (!string_is_empty(tmp))
+            strlcpy(sanitised_data, tmp, sizeof(sanitised_data));
+
+         if (tmp)
+            free(tmp);
+      }
+   }
+
+   if (string_is_empty(sanitised_data))
+      return;
+
+   /* All is well - can copy result */
+   strlcpy(str, sanitised_data, len);
+}
+
+/* Extracts game information from specified node.
+ * Returns false if node is invalid */
+static bool logiqx_dat_parse_game_node(
+      rxml_node_t *node, logiqx_dat_game_info_t *game_info)
+{
+   const char *game_name   = NULL;
+   const char *is_bios     = NULL;
+   const char *is_runnable = NULL;
+   rxml_node_t *info_node  = NULL;
+   bool description_found  = false;
+   bool year_found         = false;
+   bool manufacturer_found = false;
+
+   if (!logiqx_dat_is_game_node(node))
+      return false;
+
+   if (!game_info)
+      return false;
+
+   /* Initialise logiqx_dat_game_info_t object */
+   game_info->name[0]         = '\0';
+   game_info->description[0]  = '\0';
+   game_info->year[0]         = '\0';
+   game_info->manufacturer[0] = '\0';
+   game_info->is_bios         = false;
+   game_info->is_runnable     = true;
+
+   /* Get game name */
+   game_name = rxml_node_attrib(node, "name");
+
+   if (!string_is_empty(game_name))
+      strlcpy(game_info->name, game_name, sizeof(game_info->name));
+
+   /* Get 'is bios' status */
+   is_bios = rxml_node_attrib(node, "isbios");
+
+   if (!string_is_empty(is_bios))
+      game_info->is_bios = string_is_equal(is_bios, "yes");
+
+   /* Get 'is runnable' status
+    * > Note: This attribute only exists in MAME List
+    *   XML files, but there is no harm in checking for
+    *   it generally. For normal Logiqx XML files,
+    *   'is runnable' is just the inverse of 'is bios' */
+   is_runnable = rxml_node_attrib(node, "runnable");
+
+   if (!string_is_empty(is_runnable))
+      game_info->is_runnable = string_is_equal(is_runnable, "yes");
+   else
+      game_info->is_runnable = !game_info->is_bios;
+
+   /* Loop over all game info nodes */
+   for (info_node = node->children; info_node; info_node = info_node->next)
+   {
+      const char *info_node_name = info_node->name;
+      const char *info_node_data = info_node->data;
+
+      if (string_is_empty(info_node_name))
+         continue;
+
+      /* Check description */
+      if (string_is_equal(info_node_name, "description"))
+      {
+         logiqx_dat_sanitise_element_data(
+            info_node_data, game_info->description,
+            sizeof(game_info->description));
+         description_found = true;
+      }
+      /* Check year */
+      else if (string_is_equal(info_node_name, "year"))
+      {
+         logiqx_dat_sanitise_element_data(
+            info_node_data, game_info->year,
+            sizeof(game_info->year));
+         year_found = true;
+      }
+      /* Check manufacturer */
+      else if (string_is_equal(info_node_name, "manufacturer"))
+      {
+         logiqx_dat_sanitise_element_data(
+            info_node_data, game_info->manufacturer,
+            sizeof(game_info->manufacturer));
+         manufacturer_found = true;
+      }
+
+      /* If all required entries have been found,
+       * can end loop */
+      if (description_found && year_found && manufacturer_found)
+         break;
+   }
+
+   return true;
+}
+
+/* Sets/resets internal node pointer to the first
+ * entry in the DAT file */
+void logiqx_dat_set_first(logiqx_dat_t *dat_file)
+{
+   rxml_node_t *root_node = NULL;
+
+   if (!dat_file)
+      return;
+
+   if (!dat_file->data)
+      return;
+
+   /* Get root node */
+   root_node = rxml_root_node(dat_file->data);
+
+   if (!root_node)
+   {
+      dat_file->current_node = NULL;
+      return;
+   }
+
+   /* Get pointer to initial child node */
+   dat_file->current_node = root_node->children;
+}
+
+/* Fetches game information for the current entry
+ * in the DAT file and increments the internal node
+ * pointer.
+ * Returns false if the end of the DAT file has been
+ * reached (in which case 'game_info' will be invalid) */
+bool logiqx_dat_get_next(
+      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info)
+{
+   if (!dat_file || !game_info)
+      return false;
+
+   if (!dat_file->data)
+      return false;
+
+   while (dat_file->current_node)
+   {
+      rxml_node_t *current_node = dat_file->current_node;
+
+      /* Whatever happens, internal node pointer must
+       * be 'incremented' */
+      dat_file->current_node = dat_file->current_node->next;
+
+      /* If this is a game node, extract info
+       * and return */
+      if (logiqx_dat_is_game_node(current_node))
+         return logiqx_dat_parse_game_node(current_node, game_info);
+   }
+
+   return false;
+}
+
+/* Fetches information for the specified game.
+ * Returns false if game does not exist, or arguments
+ * are invalid. */
+bool logiqx_dat_search(
+      logiqx_dat_t *dat_file, const char *game_name,
+      logiqx_dat_game_info_t *game_info)
+{
+   rxml_node_t *root_node = NULL;
+   rxml_node_t *game_node = NULL;
+
+   if (!dat_file || !game_info || string_is_empty(game_name))
+      return false;
+
+   if (!dat_file->data)
+      return false;
+
+   /* Get root node */
+   root_node = rxml_root_node(dat_file->data);
+
+   if (!root_node)
+      return false;
+
+   /* Loop over all child nodes of the DAT file */
+   for (game_node = root_node->children; game_node; game_node = game_node->next)
+   {
+      /* If this is the requested game, fetch info and return */
+      if (logiqx_dat_game_node_matches_name(game_node, game_name))
+         return logiqx_dat_parse_game_node(game_node, game_info);
+   }
+
+   return false;
+}
diff --git a/deps/libretro-common/formats/m3u/m3u_file.c b/deps/libretro-common/formats/m3u/m3u_file.c
new file mode 100644 (file)
index 0000000..00a3c73
--- /dev/null
@@ -0,0 +1,633 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (m3u_file.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <retro_miscellaneous.h>
+
+#include <string/stdstring.h>
+#include <lists/string_list.h>
+#include <file/file_path.h>
+#include <streams/file_stream.h>
+#include <array/rbuf.h>
+
+#include <formats/m3u_file.h>
+
+/* We parse the following types of entry label:
+ * - '#LABEL:<label>' non-standard, but used by
+ *   some cores
+ * - '#EXTINF:<runtime>,<label>' standard extended
+ *   M3U directive
+ * - '<content path>|<label>' non-standard, but
+ *   used by some cores
+ * All other comments/directives are ignored */
+#define M3U_FILE_COMMENT            '#'
+#define M3U_FILE_NONSTD_LABEL       "#LABEL:"
+#define M3U_FILE_EXTSTD_LABEL       "#EXTINF:"
+#define M3U_FILE_EXTSTD_LABEL_TOKEN ','
+#define M3U_FILE_RETRO_LABEL_TOKEN  '|'
+
+/* Holds all internal M3U file data
+ * > Note the awkward name: 'content_m3u_file'
+ *   If we used just 'm3u_file' here, it would
+ *   lead to conflicts elsewhere... */
+struct content_m3u_file
+{
+   char *path;
+   m3u_file_entry_t *entries;
+};
+
+/* File Initialisation / De-Initialisation */
+
+/* Reads M3U file contents from disk
+ * - Does nothing if file does not exist 
+ * - Returns false in the event of an error */
+static bool m3u_file_load(m3u_file_t *m3u_file)
+{
+   const char *file_ext      = NULL;
+   int64_t file_len          = 0;
+   uint8_t *file_buf         = NULL;
+   struct string_list *lines = NULL;
+   bool success              = false;
+   size_t i;
+   char entry_path[PATH_MAX_LENGTH];
+   char entry_label[PATH_MAX_LENGTH];
+
+   entry_path[0]  = '\0';
+   entry_label[0] = '\0';
+
+   if (!m3u_file)
+      goto end;
+
+   /* Check whether file exists
+    * > If path is empty, then an error
+    *   has occurred... */
+   if (string_is_empty(m3u_file->path))
+      goto end;
+
+   /* > File must have the correct extension */
+   file_ext = path_get_extension(m3u_file->path);
+
+   if (string_is_empty(file_ext) ||
+       !string_is_equal_noncase(file_ext, M3U_FILE_EXT))
+      goto end;
+
+   /* > If file does not exist, no action
+    *   is required */
+   if (!path_is_valid(m3u_file->path))
+   {
+      success = true;
+      goto end;
+   }
+
+   /* Read file from disk */
+   if (filestream_read_file(m3u_file->path, (void**)&file_buf, &file_len) >= 0)
+   {
+      /* Split file into lines */
+      if (file_len > 0)
+         lines = string_split((const char*)file_buf, "\n");
+
+      /* File buffer no longer required */
+      if (file_buf)
+      {
+         free(file_buf);
+         file_buf = NULL;
+      }
+   }
+   /* File IO error... */
+   else
+      goto end;
+
+   /* If file was empty, no action is required */
+   if (!lines)
+   {
+      success = true;
+      goto end;
+   }
+
+   /* Parse lines of file */
+   for (i = 0; i < lines->size; i++)
+   {
+      const char *line = lines->elems[i].data;
+
+      if (string_is_empty(line))
+         continue;
+
+      /* Determine line 'type' */
+
+      /* > '#LABEL:' */
+      if (string_starts_with_size(line, M3U_FILE_NONSTD_LABEL,
+            STRLEN_CONST(M3U_FILE_NONSTD_LABEL)))
+      {
+         /* Label is the string to the right
+          * of '#LABEL:' */
+         const char *label = line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL);
+
+         if (!string_is_empty(label))
+         {
+            strlcpy(
+                  entry_label, line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL),
+                  sizeof(entry_label));
+            string_trim_whitespace(entry_label);
+         }
+      }
+      /* > '#EXTINF:' */
+      else if (string_starts_with_size(line, M3U_FILE_EXTSTD_LABEL,
+            STRLEN_CONST(M3U_FILE_EXTSTD_LABEL)))
+      {
+         /* Label is the string to the right
+          * of the first comma */
+         const char* label_ptr = strchr(
+               line + STRLEN_CONST(M3U_FILE_EXTSTD_LABEL),
+               M3U_FILE_EXTSTD_LABEL_TOKEN);
+
+         if (!string_is_empty(label_ptr))
+         {
+            label_ptr++;
+            if (!string_is_empty(label_ptr))
+            {
+               strlcpy(entry_label, label_ptr, sizeof(entry_label));
+               string_trim_whitespace(entry_label);
+            }
+         }
+      }
+      /* > Ignore other comments/directives */
+      else if (line[0] == M3U_FILE_COMMENT)
+         continue;
+      /* > An actual 'content' line */
+      else
+      {
+         /* This is normally a file name/path, but may
+          * have the format <content path>|<label> */
+         const char *token_ptr = strchr(line, M3U_FILE_RETRO_LABEL_TOKEN);
+
+         if (token_ptr)
+         {
+            size_t len = (size_t)(1 + token_ptr - line);
+
+            /* Get entry_path segment */
+            if (len > 0)
+            {
+               memset(entry_path, 0, sizeof(entry_path));
+               strlcpy(
+                     entry_path, line,
+                     ((len < PATH_MAX_LENGTH ?
+                           len : PATH_MAX_LENGTH) * sizeof(char)));
+               string_trim_whitespace(entry_path);
+            }
+
+            /* Get entry_label segment */
+            token_ptr++;
+            if (*token_ptr != '\0')
+            {
+               strlcpy(entry_label, token_ptr, sizeof(entry_label));
+               string_trim_whitespace(entry_label);
+            }
+         }
+         else
+         {
+            /* Just a normal file name/path */
+            strlcpy(entry_path, line, sizeof(entry_path));
+            string_trim_whitespace(entry_path);
+         }
+
+         /* Add entry to file
+          * > Note: The only way that m3u_file_add_entry()
+          *   can fail here is if we run out of memory.
+          *   This is a critical error, and m3u_file must
+          *   be considered invalid in this case */
+         if (!string_is_empty(entry_path) &&
+             !m3u_file_add_entry(m3u_file, entry_path, entry_label))
+            goto end;
+
+         /* Reset entry_path/entry_label */
+         entry_path[0]  = '\0';
+         entry_label[0] = '\0';
+      }
+   }
+
+   success = true;
+
+end:
+   /* Clean up */
+   if (lines)
+   {
+      string_list_free(lines);
+      lines = NULL;
+   }
+
+   if (file_buf)
+   {
+      free(file_buf);
+      file_buf = NULL;
+   }
+
+   return success;
+}
+
+/* Creates and initialises an M3U file
+ * - If 'path' refers to an existing file,
+ *   contents is parsed
+ * - If path does not exist, an empty M3U file
+ *   is created
+ * - Returned m3u_file_t object must be free'd using
+ *   m3u_file_free()
+ * - Returns NULL in the event of an error */
+m3u_file_t *m3u_file_init(const char *path)
+{
+   m3u_file_t *m3u_file = NULL;
+   char m3u_path[PATH_MAX_LENGTH];
+
+   m3u_path[0] = '\0';
+
+   /* Sanity check */
+   if (string_is_empty(path))
+      return NULL;
+
+   /* Get 'real' file path */
+   strlcpy(m3u_path, path, sizeof(m3u_path));
+   path_resolve_realpath(m3u_path, sizeof(m3u_path), false);
+
+   if (string_is_empty(m3u_path))
+      return NULL;
+
+   /* Create m3u_file_t object */
+   m3u_file = (m3u_file_t*)malloc(sizeof(*m3u_file));
+
+   if (!m3u_file)
+      return NULL;
+
+   /* Initialise members */
+   m3u_file->path    = NULL;
+   m3u_file->entries = NULL;
+
+   /* Copy file path */
+   m3u_file->path    = strdup(m3u_path);
+
+   /* Read existing file contents from
+    * disk, if required */
+   if (!m3u_file_load(m3u_file))
+   {
+      m3u_file_free(m3u_file);
+      return NULL;
+   }
+
+   return m3u_file;
+}
+
+/* Frees specified M3U file entry */
+static void m3u_file_free_entry(m3u_file_entry_t *entry)
+{
+   if (!entry)
+      return;
+
+   if (entry->path)
+      free(entry->path);
+
+   if (entry->full_path)
+      free(entry->full_path);
+
+   if (entry->label)
+      free(entry->label);
+
+   entry->path      = NULL;
+   entry->full_path = NULL;
+   entry->label     = NULL;
+}
+
+/* Frees specified M3U file */
+void m3u_file_free(m3u_file_t *m3u_file)
+{
+   size_t i;
+
+   if (!m3u_file)
+      return;
+
+   if (m3u_file->path)
+      free(m3u_file->path);
+
+   m3u_file->path = NULL;
+
+   /* Free entries */
+   if (m3u_file->entries)
+   {
+      for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
+      {
+         m3u_file_entry_t *entry = &m3u_file->entries[i];
+         m3u_file_free_entry(entry);
+      }
+
+      RBUF_FREE(m3u_file->entries);
+   }
+
+   free(m3u_file);
+}
+
+/* Getters */
+
+/* Returns M3U file path */
+char *m3u_file_get_path(m3u_file_t *m3u_file)
+{
+   if (!m3u_file)
+      return NULL;
+
+   return m3u_file->path;
+}
+
+/* Returns number of entries in M3U file */
+size_t m3u_file_get_size(m3u_file_t *m3u_file)
+{
+   if (!m3u_file)
+      return 0;
+
+   return RBUF_LEN(m3u_file->entries);
+}
+
+/* Fetches specified M3U file entry
+ * - Returns false if 'idx' is invalid, or internal
+ *   entry is NULL */
+bool m3u_file_get_entry(
+      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry)
+{
+   if (!m3u_file ||
+       !entry ||
+       (idx >= RBUF_LEN(m3u_file->entries)))
+      return false;
+
+   *entry = &m3u_file->entries[idx];
+
+   if (!*entry)
+      return false;
+
+   return true;
+}
+
+/* Setters */
+
+/* Adds specified entry to the M3U file
+ * - Returns false if path is invalid, or
+ *   memory could not be allocated for the
+ *   entry */
+bool m3u_file_add_entry(
+      m3u_file_t *m3u_file, const char *path, const char *label)
+{
+   m3u_file_entry_t *entry = NULL;
+   size_t num_entries;
+   char full_path[PATH_MAX_LENGTH];
+
+   full_path[0] = '\0';
+
+   if (!m3u_file || string_is_empty(path))
+      return false;
+
+   /* Get current number of file entries */
+   num_entries = RBUF_LEN(m3u_file->entries);
+
+   /* Attempt to allocate memory for new entry */
+   if (!RBUF_TRYFIT(m3u_file->entries, num_entries + 1))
+      return false;
+
+   /* Allocation successful - increment array size */
+   RBUF_RESIZE(m3u_file->entries, num_entries + 1);
+
+   /* Fetch entry at end of list, and zero-initialise
+    * members */
+   entry = &m3u_file->entries[num_entries];
+   memset(entry, 0, sizeof(*entry));
+
+   /* Copy path and label */
+   entry->path = strdup(path);
+
+   if (!string_is_empty(label))
+      entry->label = strdup(label);
+
+   /* Populate 'full_path' field */
+   if (path_is_absolute(path))
+   {
+      strlcpy(full_path, path, sizeof(full_path));
+      path_resolve_realpath(full_path, sizeof(full_path), false);
+   }
+   else
+      fill_pathname_resolve_relative(
+            full_path, m3u_file->path, path,
+            sizeof(full_path));
+
+   /* Handle unforeseen errors... */
+   if (string_is_empty(full_path))
+   {
+      m3u_file_free_entry(entry);
+      return false;
+   }
+
+   entry->full_path = strdup(full_path);
+
+   return true;
+}
+
+/* Removes all entries in M3U file */
+void m3u_file_clear(m3u_file_t *m3u_file)
+{
+   size_t i;
+
+   if (!m3u_file)
+      return;
+
+   if (m3u_file->entries)
+   {
+      for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
+      {
+         m3u_file_entry_t *entry = &m3u_file->entries[i];
+         m3u_file_free_entry(entry);
+      }
+
+      RBUF_FREE(m3u_file->entries);
+   }
+}
+
+/* Saving */
+
+/* Saves M3U file to disk
+ * - Setting 'label_type' to M3U_FILE_LABEL_NONE
+ *   just outputs entry paths - this the most
+ *   common format supported by most cores
+ * - Returns false in the event of an error */
+bool m3u_file_save(
+      m3u_file_t *m3u_file, enum m3u_file_label_type label_type)
+{
+   RFILE *file = NULL;
+   size_t i;
+   char base_dir[PATH_MAX_LENGTH];
+
+   base_dir[0] = '\0';
+
+   if (!m3u_file || !m3u_file->entries)
+      return false;
+
+   /* This should never happen */
+   if (string_is_empty(m3u_file->path))
+      return false;
+
+   /* Get M3U file base directory */
+   if (find_last_slash(m3u_file->path))
+   {
+      strlcpy(base_dir, m3u_file->path, sizeof(base_dir));
+      path_basedir(base_dir);
+   }
+
+   /* Open file for writing */
+   file = filestream_open(
+         m3u_file->path,
+         RETRO_VFS_FILE_ACCESS_WRITE,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+   if (!file)
+      return false;
+
+   /* Loop over entries */
+   for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
+   {
+      m3u_file_entry_t *entry = &m3u_file->entries[i];
+      char entry_path[PATH_MAX_LENGTH];
+
+      entry_path[0] = '\0';
+
+      if (!entry || string_is_empty(entry->full_path))
+         continue;
+
+      /* When writing M3U files, entry paths are
+       * always relative */
+      if (string_is_empty(base_dir))
+         strlcpy(
+               entry_path, entry->full_path,
+               sizeof(entry_path));
+      else
+         path_relative_to(
+               entry_path, entry->full_path, base_dir,
+               sizeof(entry_path));
+
+      if (string_is_empty(entry_path))
+         continue;
+
+      /* Check if we need to write a label */
+      if (!string_is_empty(entry->label))
+      {
+         switch (label_type)
+         {
+            case M3U_FILE_LABEL_NONSTD:
+               filestream_printf(
+                     file, "%s%s\n%s\n",
+                     M3U_FILE_NONSTD_LABEL, entry->label,
+                     entry_path);
+               break;
+            case M3U_FILE_LABEL_EXTSTD:
+               filestream_printf(
+                     file, "%s%c%s\n%s\n",
+                     M3U_FILE_EXTSTD_LABEL, M3U_FILE_EXTSTD_LABEL_TOKEN, entry->label,
+                     entry_path);
+               break;
+            case M3U_FILE_LABEL_RETRO:
+               filestream_printf(
+                     file, "%s%c%s\n",
+                     entry_path, M3U_FILE_RETRO_LABEL_TOKEN, entry->label);
+               break;
+            case M3U_FILE_LABEL_NONE:
+            default:
+               filestream_printf(
+                     file, "%s\n", entry_path);
+               break;
+         }
+      }
+      /* No label - just write entry path */
+      else
+         filestream_printf(
+               file, "%s\n", entry_path);
+   }
+
+   /* Close file */
+   filestream_close(file);
+
+   return true;
+}
+
+/* Utilities */
+
+/* Internal qsort function */
+static int m3u_file_qsort_func(
+      const m3u_file_entry_t *a, const m3u_file_entry_t *b)
+{
+   if (!a || !b)
+      return 0;
+
+   if (string_is_empty(a->full_path) || string_is_empty(b->full_path))
+      return 0;
+
+   return strcasecmp(a->full_path, b->full_path);
+}
+
+/* Sorts M3U file entries in alphabetical order */
+void m3u_file_qsort(m3u_file_t *m3u_file)
+{
+   size_t num_entries;
+
+   if (!m3u_file)
+      return;
+
+   num_entries = RBUF_LEN(m3u_file->entries);
+
+   if (num_entries < 2)
+      return;
+
+   qsort(
+         m3u_file->entries, num_entries,
+         sizeof(m3u_file_entry_t),
+         (int (*)(const void *, const void *))m3u_file_qsort_func);
+}
+
+/* Returns true if specified path corresponds
+ * to an M3U file (simple convenience function) */
+bool m3u_file_is_m3u(const char *path)
+{
+   const char *file_ext = NULL;
+   int32_t file_size;
+
+   if (string_is_empty(path))
+      return false;
+
+   /* Check file extension */
+   file_ext = path_get_extension(path);
+
+   if (string_is_empty(file_ext))
+      return false;
+
+   if (!string_is_equal_noncase(file_ext, M3U_FILE_EXT))
+      return false;
+
+   /* Ensure file exists */
+   if (!path_is_valid(path))
+      return false;
+
+   /* Ensure we have non-zero file size */
+   file_size = path_get_size(path);
+
+   if (file_size <= 0)
+      return false;
+
+   return true;
+}
diff --git a/deps/libretro-common/formats/png/rpng.c b/deps/libretro-common/formats/png/rpng.c
new file mode 100644 (file)
index 0000000..9cd19f6
--- /dev/null
@@ -0,0 +1,1251 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rpng.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef GEKKO
+#include <malloc.h>
+#endif
+
+#include <boolean.h>
+#include <formats/image.h>
+#include <formats/rpng.h>
+#include <streams/trans_stream.h>
+#include <string/stdstring.h>
+
+#include "rpng_internal.h"
+
+enum png_ihdr_color_type
+{
+   PNG_IHDR_COLOR_GRAY       = 0,
+   PNG_IHDR_COLOR_RGB        = 2,
+   PNG_IHDR_COLOR_PLT        = 3,
+   PNG_IHDR_COLOR_GRAY_ALPHA = 4,
+   PNG_IHDR_COLOR_RGBA       = 6
+};
+
+enum png_line_filter
+{
+   PNG_FILTER_NONE = 0,
+   PNG_FILTER_SUB,
+   PNG_FILTER_UP,
+   PNG_FILTER_AVERAGE,
+   PNG_FILTER_PAETH
+};
+
+enum png_chunk_type
+{
+   PNG_CHUNK_NOOP = 0,
+   PNG_CHUNK_ERROR,
+   PNG_CHUNK_IHDR,
+   PNG_CHUNK_IDAT,
+   PNG_CHUNK_PLTE,
+   PNG_CHUNK_tRNS,
+   PNG_CHUNK_IEND
+};
+
+struct adam7_pass
+{
+   unsigned x;
+   unsigned y;
+   unsigned stride_x;
+   unsigned stride_y;
+};
+
+struct idat_buffer
+{
+   uint8_t *data;
+   size_t size;
+};
+
+enum rpng_process_flags
+{
+   RPNG_PROCESS_FLAG_INFLATE_INITIALIZED    = (1 << 0),
+   RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED = (1 << 1),
+   RPNG_PROCESS_FLAG_PASS_INITIALIZED       = (1 << 2)
+};
+
+struct rpng_process
+{
+   uint32_t *data;
+   uint32_t *palette;
+   void *stream;
+   const struct trans_stream_backend *stream_backend;
+   uint8_t *prev_scanline;
+   uint8_t *decoded_scanline;
+   uint8_t *inflate_buf;
+   size_t restore_buf_size;
+   size_t adam7_restore_buf_size;
+   size_t data_restore_buf_size;
+   size_t inflate_buf_size;
+   size_t avail_in;
+   size_t avail_out;
+   size_t total_out;
+   size_t pass_size;
+   struct png_ihdr ihdr; /* uint32_t alignment */
+   unsigned bpp;
+   unsigned pitch;
+   unsigned h;
+   unsigned pass_width;
+   unsigned pass_height;
+   unsigned pass_pos;
+   uint8_t flags;
+};
+
+enum rpng_flags
+{
+   RPNG_FLAG_HAS_IHDR = (1 << 0),
+   RPNG_FLAG_HAS_IDAT = (1 << 1),
+   RPNG_FLAG_HAS_IEND = (1 << 2),
+   RPNG_FLAG_HAS_PLTE = (1 << 3),
+   RPNG_FLAG_HAS_TRNS = (1 << 4)
+};
+
+struct rpng
+{
+   struct rpng_process *process;
+   uint8_t *buff_data;
+   uint8_t *buff_end;
+   struct idat_buffer idat_buf; /* ptr alignment */
+   struct png_ihdr ihdr; /* uint32 alignment */
+   uint32_t palette[256];
+   uint8_t flags;
+};
+
+static const struct adam7_pass rpng_passes[] = {
+   { 0, 0, 8, 8 },
+   { 4, 0, 8, 8 },
+   { 0, 4, 4, 8 },
+   { 2, 0, 4, 4 },
+   { 0, 2, 2, 4 },
+   { 1, 0, 2, 2 },
+   { 0, 1, 1, 2 },
+};
+
+static INLINE uint32_t rpng_dword_be(const uint8_t *buf)
+{
+   return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
+}
+
+#if defined(DEBUG) || defined(RPNG_TEST)
+static bool rpng_process_ihdr(struct png_ihdr *ihdr)
+{
+   uint8_t ihdr_depth = ihdr->depth;
+
+   switch (ihdr->color_type)
+   {
+      case PNG_IHDR_COLOR_RGB:
+      case PNG_IHDR_COLOR_GRAY_ALPHA:
+      case PNG_IHDR_COLOR_RGBA:
+         if (ihdr_depth != 8 && ihdr_depth != 16)
+         {
+            fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
+            return false;
+         }
+         break;
+      case PNG_IHDR_COLOR_GRAY:
+         /* Valid bitdepths are: 1, 2, 4, 8, 16 */
+         if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
+         {
+            fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
+            return false;
+         }
+         break;
+      case PNG_IHDR_COLOR_PLT:
+         /* Valid bitdepths are: 1, 2, 4, 8 */
+         if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)
+         {
+            fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
+            return false;
+         }
+         break;
+      default:
+         fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
+         return false;
+   }
+
+#ifdef RPNG_TEST
+   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
+         ihdr->width, ihdr->height,
+         ihdr_depth, (ihdr->color_type == PNG_IHDR_COLOR_PLT) ? "yes" : "no",
+         (ihdr->color_type & PNG_IHDR_COLOR_RGB)              ? "yes" : "no",
+         (ihdr->color_type & PNG_IHDR_COLOR_GRAY_ALPHA)       ? "yes" : "no",
+         ihdr->interlace == 1 ? "yes" : "no");
+#endif
+
+   return true;
+}
+#else
+static bool rpng_process_ihdr(struct png_ihdr *ihdr)
+{
+   uint8_t ihdr_depth = ihdr->depth;
+
+   switch (ihdr->color_type)
+   {
+      case PNG_IHDR_COLOR_RGB:
+      case PNG_IHDR_COLOR_GRAY_ALPHA:
+      case PNG_IHDR_COLOR_RGBA:
+         if (ihdr_depth != 8 && ihdr_depth != 16)
+            return false;
+         break;
+      case PNG_IHDR_COLOR_GRAY:
+         /* Valid bitdepths are: 1, 2, 4, 8, 16 */
+         if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
+            return false;
+         break;
+      case PNG_IHDR_COLOR_PLT:
+         /* Valid bitdepths are: 1, 2, 4, 8 */
+         if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)
+            return false;
+         break;
+      default:
+         return false;
+   }
+
+   return true;
+}
+#endif
+
+static void rpng_reverse_filter_copy_line_rgb(uint32_t *data,
+      const uint8_t *decoded, unsigned width, unsigned bpp)
+{
+   int i;
+
+   bpp /= 8;
+
+   for (i = 0; i < (int)width; i++)
+   {
+      uint32_t r, g, b;
+
+      r        = *decoded;
+      decoded += bpp;
+      g        = *decoded;
+      decoded += bpp;
+      b        = *decoded;
+      decoded += bpp;
+      data[i]  = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
+   }
+}
+
+static void rpng_reverse_filter_copy_line_rgba(uint32_t *data,
+      const uint8_t *decoded, unsigned width, unsigned bpp)
+{
+   int i;
+
+   bpp /= 8;
+
+   for (i = 0; i < (int)width; i++)
+   {
+      uint32_t r, g, b, a;
+      r        = *decoded;
+      decoded += bpp;
+      g        = *decoded;
+      decoded += bpp;
+      b        = *decoded;
+      decoded += bpp;
+      a        = *decoded;
+      decoded += bpp;
+      data[i]  = (a << 24) | (r << 16) | (g << 8) | (b << 0);
+   }
+}
+
+static void rpng_reverse_filter_copy_line_bw(uint32_t *data,
+      const uint8_t *decoded, unsigned width, unsigned depth)
+{
+   int i;
+   unsigned bit;
+   static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
+   unsigned mul, mask;
+
+   if (depth == 16)
+   {
+      for (i = 0; i < (int)width; i++)
+      {
+         uint32_t val = decoded[i << 1];
+         data[i]      = (val * 0x010101) | (0xffu << 24);
+      }
+      return;
+   }
+
+   mul  = mul_table[depth];
+   mask = (1 << depth) - 1;
+   bit  = 0;
+
+   for (i = 0; i < (int)width; i++, bit += depth)
+   {
+      unsigned byte = bit >> 3;
+      unsigned val  = decoded[byte] >> (8 - depth - (bit & 7));
+
+      val          &= mask;
+      val          *= mul;
+      data[i]       = (val * 0x010101) | (0xffu << 24);
+   }
+}
+
+static void rpng_reverse_filter_copy_line_gray_alpha(uint32_t *data,
+      const uint8_t *decoded, unsigned width,
+      unsigned bpp)
+{
+   int i;
+
+   bpp /= 8;
+
+   for (i = 0; i < (int)width; i++)
+   {
+      uint32_t gray, alpha;
+
+      gray     = *decoded;
+      decoded += bpp;
+      alpha    = *decoded;
+      decoded += bpp;
+
+      data[i]  = (gray * 0x010101) | (alpha << 24);
+   }
+}
+
+static void rpng_reverse_filter_copy_line_plt(uint32_t *data,
+      const uint8_t *decoded, unsigned width,
+      unsigned depth, const uint32_t *palette)
+{
+   switch (depth)
+   {
+      case 1:
+         {
+            int i;
+            unsigned w = width / 8;
+            for (i = 0; i < (int)w; i++, decoded++)
+            {
+               *data++ = palette[(*decoded >> 7) & 1];
+               *data++ = palette[(*decoded >> 6) & 1];
+               *data++ = palette[(*decoded >> 5) & 1];
+               *data++ = palette[(*decoded >> 4) & 1];
+               *data++ = palette[(*decoded >> 3) & 1];
+               *data++ = palette[(*decoded >> 2) & 1];
+               *data++ = palette[(*decoded >> 1) & 1];
+               *data++ = palette[*decoded & 1];
+            }
+
+            switch (width & 7)
+            {
+               case 7:
+                  data[6] = palette[(*decoded >> 1) & 1];
+               case 6:
+                  data[5] = palette[(*decoded >> 2) & 1];
+               case 5:
+                  data[4] = palette[(*decoded >> 3) & 1];
+               case 4:
+                  data[3] = palette[(*decoded >> 4) & 1];
+               case 3:
+                  data[2] = palette[(*decoded >> 5) & 1];
+               case 2:
+                  data[1] = palette[(*decoded >> 6) & 1];
+               case 1:
+                  data[0] = palette[(*decoded >> 7) & 1];
+                  break;
+            }
+         }
+         break;
+
+      case 2:
+         {
+            int i;
+            unsigned w = width / 4;
+            for (i = 0; i < (int)w; i++, decoded++)
+            {
+               *data++ = palette[(*decoded >> 6) & 3];
+               *data++ = palette[(*decoded >> 4) & 3];
+               *data++ = palette[(*decoded >> 2) & 3];
+               *data++ = palette[*decoded & 3];
+            }
+
+            switch (width & 3)
+            {
+               case 3:
+                  data[2] = palette[(*decoded >> 2) & 3];
+               case 2:
+                  data[1] = palette[(*decoded >> 4) & 3];
+               case 1:
+                  data[0] = palette[(*decoded >> 6) & 3];
+                  break;
+            }
+         }
+         break;
+
+      case 4:
+         {
+            int i;
+            unsigned w = width / 2;
+            for (i = 0; i < (int)w; i++, decoded++)
+            {
+               *data++ = palette[*decoded >> 4];
+               *data++ = palette[*decoded & 0x0f];
+            }
+
+            if (width & 1)
+               *data = palette[*decoded >> 4];
+         }
+         break;
+
+      case 8:
+         {
+            int i;
+            for (i = 0; i < (int)width; i++, decoded++, data++)
+               *data = palette[*decoded];
+         }
+         break;
+   }
+}
+
+static void rpng_pass_geom(const struct png_ihdr *ihdr,
+      unsigned width, unsigned height,
+      unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size)
+{
+   unsigned bpp   = 0;
+   unsigned pitch = 0;
+
+   switch (ihdr->color_type)
+   {
+      case PNG_IHDR_COLOR_GRAY:
+         bpp   = (ihdr->depth + 7) / 8;
+         pitch = (ihdr->width * ihdr->depth + 7) / 8;
+         break;
+      case PNG_IHDR_COLOR_RGB:
+         bpp   = (ihdr->depth * 3 + 7) / 8;
+         pitch = (ihdr->width * ihdr->depth * 3 + 7) / 8;
+         break;
+      case PNG_IHDR_COLOR_PLT:
+         bpp   = (ihdr->depth + 7) / 8;
+         pitch = (ihdr->width * ihdr->depth + 7) / 8;
+         break;
+      case PNG_IHDR_COLOR_GRAY_ALPHA:
+         bpp   = (ihdr->depth * 2 + 7) / 8;
+         pitch = (ihdr->width * ihdr->depth * 2 + 7) / 8;
+         break;
+      case PNG_IHDR_COLOR_RGBA:
+         bpp   = (ihdr->depth * 4 + 7) / 8;
+         pitch = (ihdr->width * ihdr->depth * 4 + 7) / 8;
+         break;
+      default:
+         break;
+   }
+
+   if (pass_size)
+      *pass_size = (pitch + 1) * ihdr->height;
+   if (bpp_out)
+      *bpp_out   = bpp;
+   if (pitch_out)
+      *pitch_out = pitch;
+}
+
+static void rpng_reverse_filter_adam7_deinterlace_pass(uint32_t *data,
+      const struct png_ihdr *ihdr,
+      const uint32_t *input, unsigned pass_width, unsigned pass_height,
+      const struct adam7_pass *pass)
+{
+   unsigned x, y;
+
+   data += pass->y * ihdr->width + pass->x;
+
+   for (y = 0; y < pass_height;
+         y++, data += ihdr->width * pass->stride_y, input += pass_width)
+   {
+      uint32_t *out = data;
+
+      for (x = 0; x < pass_width; x++, out += pass->stride_x)
+         *out = input[x];
+   }
+}
+
+static void rpng_reverse_filter_deinit(struct rpng_process *pngp)
+{
+   if (!pngp)
+      return;
+   if (pngp->decoded_scanline)
+      free(pngp->decoded_scanline);
+   pngp->decoded_scanline = NULL;
+   if (pngp->prev_scanline)
+      free(pngp->prev_scanline);
+   pngp->prev_scanline    = NULL;
+
+   pngp->flags           &= ~RPNG_PROCESS_FLAG_PASS_INITIALIZED;
+   pngp->h                = 0;
+}
+
+static int rpng_reverse_filter_init(const struct png_ihdr *ihdr,
+      struct rpng_process *pngp)
+{
+   size_t pass_size;
+
+   if (   !(pngp->flags & RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED) 
+         && ihdr->interlace)
+   {
+      if (     ihdr->width  <= rpng_passes[pngp->pass_pos].x
+            || ihdr->height <= rpng_passes[pngp->pass_pos].y) /* Empty pass */
+         return 1;
+
+      pngp->pass_width  = (ihdr->width -
+            rpng_passes[pngp->pass_pos].x + rpng_passes[pngp->pass_pos].stride_x
+- 1) / rpng_passes[pngp->pass_pos].stride_x;
+      pngp->pass_height = (ihdr->height - rpng_passes[pngp->pass_pos].y +
+            rpng_passes[pngp->pass_pos].stride_y - 1) / rpng_passes[pngp->pass_pos].stride_y;
+
+      if (!(pngp->data = (uint32_t*)malloc(
+            pngp->pass_width * pngp->pass_height * sizeof(uint32_t))))
+         return -1;
+
+      pngp->ihdr        = *ihdr;
+      pngp->ihdr.width  = pngp->pass_width;
+      pngp->ihdr.height = pngp->pass_height;
+
+      rpng_pass_geom(&pngp->ihdr, pngp->pass_width,
+            pngp->pass_height, NULL, NULL, &pngp->pass_size);
+
+      if (pngp->pass_size > pngp->total_out)
+      {
+         free(pngp->data);
+         pngp->data = NULL;
+         return -1;
+      }
+
+      pngp->flags |= RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;
+
+      return 0;
+   }
+
+   if (pngp->flags & RPNG_PROCESS_FLAG_PASS_INITIALIZED)
+      return 0;
+
+   rpng_pass_geom(ihdr, ihdr->width, ihdr->height, &pngp->bpp, &pngp->pitch, &pass_size);
+
+   if (pngp->total_out < pass_size)
+      return -1;
+
+   pngp->restore_buf_size      = 0;
+   pngp->data_restore_buf_size = 0;
+   pngp->prev_scanline         = (uint8_t*)calloc(1, pngp->pitch);
+   pngp->decoded_scanline      = (uint8_t*)calloc(1, pngp->pitch);
+
+   if (!pngp->prev_scanline || !pngp->decoded_scanline)
+      goto error;
+
+   pngp->h                    = 0;
+   pngp->flags               |= RPNG_PROCESS_FLAG_PASS_INITIALIZED;
+
+   return 0;
+
+error:
+   rpng_reverse_filter_deinit(pngp);
+   return -1;
+}
+
+static int rpng_reverse_filter_copy_line(uint32_t *data,
+      const struct png_ihdr *ihdr,
+      struct rpng_process *pngp, unsigned filter)
+{
+   unsigned i;
+
+   switch (filter)
+   {
+      case PNG_FILTER_NONE:
+         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
+         break;
+      case PNG_FILTER_SUB:
+         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
+         for (i = pngp->bpp; i < pngp->pitch; i++)
+            pngp->decoded_scanline[i] += pngp->decoded_scanline[i - pngp->bpp];
+         break;
+      case PNG_FILTER_UP:
+         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
+         for (i = 0; i < pngp->pitch; i++)
+            pngp->decoded_scanline[i] += pngp->prev_scanline[i];
+         break;
+      case PNG_FILTER_AVERAGE:
+         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
+         for (i = 0; i < pngp->bpp; i++)
+         {
+            uint8_t avg = pngp->prev_scanline[i] >> 1;
+            pngp->decoded_scanline[i] += avg;
+         }
+         for (i = pngp->bpp; i < pngp->pitch; i++)
+         {
+            uint8_t avg = (pngp->decoded_scanline[i - pngp->bpp] + pngp->prev_scanline[i]) >> 1;
+            pngp->decoded_scanline[i] += avg;
+         }
+         break;
+      case PNG_FILTER_PAETH:
+         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
+         for (i = 0; i < pngp->bpp; i++)
+            pngp->decoded_scanline[i] += pngp->prev_scanline[i];
+         for (i = pngp->bpp; i < pngp->pitch; i++)
+            pngp->decoded_scanline[i] += paeth(pngp->decoded_scanline[i - pngp->bpp],
+                  pngp->prev_scanline[i], pngp->prev_scanline[i - pngp->bpp]);
+         break;
+      default:
+         return IMAGE_PROCESS_ERROR_END;
+   }
+
+   switch (ihdr->color_type)
+   {
+      case PNG_IHDR_COLOR_GRAY:
+         rpng_reverse_filter_copy_line_bw(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
+         break;
+      case PNG_IHDR_COLOR_RGB:
+         rpng_reverse_filter_copy_line_rgb(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
+         break;
+      case PNG_IHDR_COLOR_PLT:
+         rpng_reverse_filter_copy_line_plt(
+               data, pngp->decoded_scanline, ihdr->width,
+               ihdr->depth, pngp->palette);
+         break;
+      case PNG_IHDR_COLOR_GRAY_ALPHA:
+         rpng_reverse_filter_copy_line_gray_alpha(data, pngp->decoded_scanline, ihdr->width,
+               ihdr->depth);
+         break;
+      case PNG_IHDR_COLOR_RGBA:
+         rpng_reverse_filter_copy_line_rgba(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
+         break;
+   }
+
+   memcpy(pngp->prev_scanline, pngp->decoded_scanline, pngp->pitch);
+
+   return IMAGE_PROCESS_NEXT;
+}
+
+static int rpng_reverse_filter_regular_iterate(
+      uint32_t **data, const struct png_ihdr *ihdr,
+      struct rpng_process *pngp)
+{
+   int ret = IMAGE_PROCESS_END;
+   if (pngp->h < ihdr->height)
+   {
+      unsigned filter         = *pngp->inflate_buf++;
+      pngp->restore_buf_size += 1;
+      ret                     = rpng_reverse_filter_copy_line(*data,
+            ihdr, pngp, filter);
+      if (ret == IMAGE_PROCESS_END || ret == IMAGE_PROCESS_ERROR_END)
+         goto end;
+   }
+   else
+      goto end;
+
+   pngp->h++;
+   pngp->inflate_buf           += pngp->pitch;
+   pngp->restore_buf_size      += pngp->pitch;
+
+   *data                       += ihdr->width;
+   pngp->data_restore_buf_size += ihdr->width;
+
+   return IMAGE_PROCESS_NEXT;
+
+end:
+   rpng_reverse_filter_deinit(pngp);
+
+   pngp->inflate_buf -= pngp->restore_buf_size;
+   *data             -= pngp->data_restore_buf_size;
+   pngp->data_restore_buf_size = 0;
+   return ret;
+}
+
+static int rpng_reverse_filter_adam7_iterate(uint32_t **data_,
+      const struct png_ihdr *ihdr,
+      struct rpng_process *pngp)
+{
+   int        ret = 0;
+   bool   to_next = pngp->pass_pos < ARRAY_SIZE(rpng_passes);
+   uint32_t *data = *data_;
+
+   if (!to_next)
+      return IMAGE_PROCESS_END;
+
+   if ((ret = rpng_reverse_filter_init(ihdr, pngp)) == 1)
+      return IMAGE_PROCESS_NEXT;
+   else if (ret == -1)
+      return IMAGE_PROCESS_ERROR_END;
+
+   if (rpng_reverse_filter_init(&pngp->ihdr, pngp) == -1)
+      return IMAGE_PROCESS_ERROR;
+
+   do
+   {
+      ret = rpng_reverse_filter_regular_iterate(&pngp->data,
+            &pngp->ihdr, pngp);
+   } while (ret == IMAGE_PROCESS_NEXT);
+
+   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
+      return IMAGE_PROCESS_ERROR;
+
+   pngp->inflate_buf            += pngp->pass_size;
+   pngp->adam7_restore_buf_size += pngp->pass_size;
+
+   pngp->total_out              -= pngp->pass_size;
+
+   rpng_reverse_filter_adam7_deinterlace_pass(data,
+         ihdr, pngp->data, pngp->pass_width, pngp->pass_height,
+         &rpng_passes[pngp->pass_pos]);
+
+   free(pngp->data);
+
+   pngp->data                   = NULL;
+   pngp->pass_width             = 0;
+   pngp->pass_height            = 0;
+   pngp->pass_size              = 0;
+   pngp->flags                 &= ~RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;
+
+   return IMAGE_PROCESS_NEXT;
+}
+
+static int rpng_reverse_filter_adam7(uint32_t **data_,
+      const struct png_ihdr *ihdr,
+      struct rpng_process *pngp)
+{
+   int ret = rpng_reverse_filter_adam7_iterate(data_,
+         ihdr, pngp);
+
+   switch (ret)
+   {
+      case IMAGE_PROCESS_ERROR_END:
+      case IMAGE_PROCESS_END:
+         break;
+      case IMAGE_PROCESS_NEXT:
+         pngp->pass_pos++;
+         return 0;
+      case IMAGE_PROCESS_ERROR:
+         if (pngp->data)
+         {
+            free(pngp->data);
+            pngp->data = NULL;
+         }
+         pngp->inflate_buf -= pngp->adam7_restore_buf_size;
+         pngp->adam7_restore_buf_size = 0;
+         return -1;
+   }
+
+   pngp->inflate_buf            -= pngp->adam7_restore_buf_size;
+   pngp->adam7_restore_buf_size  = 0;
+   return ret;
+}
+
+static int rpng_load_image_argb_process_inflate_init(
+      rpng_t *rpng, uint32_t **data)
+{
+   bool zstatus;
+   enum trans_stream_error terror;
+   uint32_t rd, wn;
+   struct rpng_process *process = (struct rpng_process*)rpng->process;
+   bool to_continue        = (process->avail_in > 0
+         && process->avail_out > 0);
+
+   if (!to_continue)
+      goto end;
+
+   zstatus = process->stream_backend->trans(process->stream, false, &rd, &wn, &terror);
+
+   if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
+      goto error;
+
+   process->avail_in -= rd;
+   process->avail_out -= wn;
+   process->total_out += wn;
+
+   if (terror)
+      return 0;
+
+end:
+   process->stream_backend->stream_free(process->stream);
+   process->stream = NULL;
+
+#ifdef GEKKO
+   /* we often use these in textures, make sure they're 32-byte aligned */
+   *data = (uint32_t*)memalign(32, rpng->ihdr.width *
+         rpng->ihdr.height * sizeof(uint32_t));
+#else
+   *data = (uint32_t*)malloc(rpng->ihdr.width *
+         rpng->ihdr.height * sizeof(uint32_t));
+#endif
+   if (!*data)
+      goto false_end;
+
+   process->adam7_restore_buf_size = 0;
+   process->restore_buf_size       = 0;
+   process->palette                = rpng->palette;
+
+   if (rpng->ihdr.interlace != 1)
+      if (rpng_reverse_filter_init(&rpng->ihdr, process) == -1)
+         goto false_end;
+
+   process->flags              |=  RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;
+   return 1;
+
+error:
+false_end:
+   process->flags              &= ~RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;
+   return -1;
+}
+
+static bool rpng_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)
+{
+   uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk_size);
+
+   if (!new_buffer)
+      return false;
+
+   buf->data  = new_buffer;
+   return true;
+}
+
+static struct rpng_process *rpng_process_init(rpng_t *rpng)
+{
+   uint8_t *inflate_buf            = NULL;
+   struct rpng_process *process    = (struct rpng_process*)malloc(sizeof(*process));
+
+   if (!process)
+      return NULL;
+
+   process->flags                  = 0;
+   process->prev_scanline          = NULL;
+   process->decoded_scanline       = NULL;
+   process->inflate_buf            = NULL;
+
+   process->ihdr.width             = 0;
+   process->ihdr.height            = 0;
+   process->ihdr.depth             = 0;
+   process->ihdr.color_type        = 0;
+   process->ihdr.compression       = 0;
+   process->ihdr.filter            = 0;
+   process->ihdr.interlace         = 0;
+
+   process->restore_buf_size       = 0;
+   process->adam7_restore_buf_size = 0;
+   process->data_restore_buf_size  = 0;
+   process->inflate_buf_size       = 0;
+   process->avail_in               = 0;
+   process->avail_out              = 0;
+   process->total_out              = 0;
+   process->pass_size              = 0;
+   process->bpp                    = 0;
+   process->pitch                  = 0;
+   process->h                      = 0;
+   process->pass_width             = 0;
+   process->pass_height            = 0;
+   process->pass_pos               = 0;
+   process->data                   = 0;
+   process->palette                = 0;
+   process->stream                 = NULL;
+   process->stream_backend         = trans_stream_get_zlib_inflate_backend();
+
+   rpng_pass_geom(&rpng->ihdr, rpng->ihdr.width,
+         rpng->ihdr.height, NULL, NULL, &process->inflate_buf_size);
+   if (rpng->ihdr.interlace == 1) /* To be sure. */
+      process->inflate_buf_size *= 2;
+
+   process->stream = process->stream_backend->stream_new();
+
+   if (!process->stream)
+   {
+      free(process);
+      return NULL;
+   }
+
+   inflate_buf = (uint8_t*)malloc(process->inflate_buf_size);
+   if (!inflate_buf)
+      goto error;
+
+   process->inflate_buf = inflate_buf;
+   process->avail_in    = rpng->idat_buf.size;
+   process->avail_out   = process->inflate_buf_size;
+
+   process->stream_backend->set_in(
+         process->stream,
+         rpng->idat_buf.data,
+         (uint32_t)rpng->idat_buf.size);
+   process->stream_backend->set_out(
+         process->stream,
+         process->inflate_buf,
+         (uint32_t)process->inflate_buf_size);
+
+   return process;
+
+error:
+   if (process)
+   {
+      if (process->stream)
+         process->stream_backend->stream_free(process->stream);
+      free(process);
+   }
+   return NULL;
+}
+
+/**
+ * rpng_read_chunk_header:
+ *
+ * Leaf function.
+ *
+ * @return The PNG type of the memory chunk (i.e. IHDR, IDAT, IEND,
+   PLTE, and/or tRNS)
+ **/
+static enum png_chunk_type rpng_read_chunk_header(
+      uint8_t *buf, uint32_t chunk_size)
+{
+   int i;
+   char type[4];
+
+   for (i = 0; i < 4; i++)
+   {
+      uint8_t byte = buf[i + 4];
+
+      /* All four bytes of the chunk type must be
+       * ASCII letters (codes 65-90 and 97-122) */
+      if ((byte < 65) || ((byte > 90) && (byte < 97)) || (byte > 122))
+         return PNG_CHUNK_ERROR;
+      type[i]      = byte;
+   }
+
+   if (     
+            type[0] == 'I'
+         && type[1] == 'H'
+         && type[2] == 'D'
+         && type[3] == 'R'
+      )
+      return PNG_CHUNK_IHDR;
+   else if
+      (
+          type[0] == 'I'
+       && type[1] == 'D'
+       && type[2] == 'A'
+       && type[3] == 'T'
+      )
+         return PNG_CHUNK_IDAT;
+   else if
+      (
+          type[0] == 'I'
+       && type[1] == 'E'
+       && type[2] == 'N'
+       && type[3] == 'D'
+      )
+         return PNG_CHUNK_IEND;
+   else if
+      (
+          type[0] == 'P'
+       && type[1] == 'L'
+       && type[2] == 'T'
+       && type[3] == 'E'
+      )
+         return PNG_CHUNK_PLTE;
+   else if
+      (
+          type[0] == 't'
+       && type[1] == 'R'
+       && type[2] == 'N'
+       && type[3] == 'S'
+      )
+         return PNG_CHUNK_tRNS;
+
+   return PNG_CHUNK_NOOP;
+}
+
+bool rpng_iterate_image(rpng_t *rpng)
+{
+   unsigned i;
+   uint8_t *buf             = (uint8_t*)rpng->buff_data;
+   uint32_t chunk_size      = 0;
+
+   /* Check whether data buffer pointer is valid */
+   if (buf > rpng->buff_end)
+      return false;
+
+   /* Check whether reading the header will overflow
+    * the data buffer */
+   if (rpng->buff_end - buf < 8)
+      return false;
+
+   chunk_size = rpng_dword_be(buf);
+
+   /* Check whether chunk will overflow the data buffer */
+   if (buf + 8 + chunk_size > rpng->buff_end)
+      return false;
+
+   switch (rpng_read_chunk_header(buf, chunk_size))
+   {
+      case PNG_CHUNK_NOOP:
+      default:
+         break;
+
+      case PNG_CHUNK_ERROR:
+         return false;
+
+      case PNG_CHUNK_IHDR:
+         if (     (rpng->flags & RPNG_FLAG_HAS_IHDR) 
+               || (rpng->flags & RPNG_FLAG_HAS_IDAT)
+               || (rpng->flags & RPNG_FLAG_HAS_IEND))
+            return false;
+
+         if (chunk_size != 13)
+            return false;
+
+         buf                    += 4 + 4;
+
+         rpng->ihdr.width        = rpng_dword_be(buf + 0);
+         rpng->ihdr.height       = rpng_dword_be(buf + 4);
+         rpng->ihdr.depth        = buf[8];
+         rpng->ihdr.color_type   = buf[9];
+         rpng->ihdr.compression  = buf[10];
+         rpng->ihdr.filter       = buf[11];
+         rpng->ihdr.interlace    = buf[12];
+
+         if (     rpng->ihdr.width  == 0 
+               || rpng->ihdr.height == 0 
+               /* ensure multiplications don't overflow and wrap around, that'd give buffer overflow crashes */
+               || (uint64_t)rpng->ihdr.width*rpng->ihdr.height*sizeof(uint32_t) >= 0x80000000)
+            return false;
+
+         if (!rpng_process_ihdr(&rpng->ihdr))
+            return false;
+
+         if (rpng->ihdr.compression != 0)
+         {
+#if defined(DEBUG) || defined(RPNG_TEST)
+            fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
+#endif
+            return false;
+         }
+
+         rpng->flags   |= RPNG_FLAG_HAS_IHDR;
+         break;
+
+      case PNG_CHUNK_PLTE:
+         {
+            int i;
+            unsigned entries = chunk_size / 3;
+
+            if (entries > 256)
+               return false;
+            if (chunk_size % 3)
+               return false;
+
+            if (     !(rpng->flags & RPNG_FLAG_HAS_IHDR)
+                  ||  (rpng->flags & RPNG_FLAG_HAS_PLTE)
+                  ||  (rpng->flags & RPNG_FLAG_HAS_IEND)
+                  ||  (rpng->flags & RPNG_FLAG_HAS_IDAT)
+                  ||  (rpng->flags & RPNG_FLAG_HAS_TRNS))
+               return false;
+
+            buf += 8;
+
+            for (i = 0; i < (int)entries; i++)
+            {
+               uint32_t r       = buf[3 * i + 0];
+               uint32_t g       = buf[3 * i + 1];
+               uint32_t b       = buf[3 * i + 2];
+               rpng->palette[i] = (r << 16) | (g << 8) | (b << 0) | (0xffu << 24);
+            }
+
+            rpng->flags        |= RPNG_FLAG_HAS_PLTE;
+         }
+         break;
+
+      case PNG_CHUNK_tRNS:
+         if (rpng->flags & RPNG_FLAG_HAS_IDAT)
+            return false;
+
+         if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT)
+         {
+            int i;
+            uint32_t *palette;
+            /* we should compare with the number of palette entries */
+            if (chunk_size > 256)
+               return false;
+
+            buf    += 8;
+            palette = rpng->palette;
+
+            for (i = 0; i < (int)chunk_size; i++, buf++, palette++)
+               *palette = (*palette & 0x00ffffff) | (unsigned)*buf << 24;
+         }
+         /* TODO: support colorkey in grayscale and truecolor images */
+
+         rpng->flags         |= RPNG_FLAG_HAS_TRNS;
+         break;
+
+      case PNG_CHUNK_IDAT:
+         if (     !(rpng->flags & RPNG_FLAG_HAS_IHDR) 
+               ||  (rpng->flags & RPNG_FLAG_HAS_IEND)
+               ||  (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT 
+                  && 
+                  !(rpng->flags & RPNG_FLAG_HAS_PLTE)))
+            return false;
+
+         if (!rpng_realloc_idat(&rpng->idat_buf, chunk_size))
+            return false;
+
+         buf += 8;
+
+         for (i = 0; i < chunk_size; i++)
+            rpng->idat_buf.data[i + rpng->idat_buf.size] = buf[i];
+
+         rpng->idat_buf.size += chunk_size;
+
+         rpng->flags         |= RPNG_FLAG_HAS_IDAT;
+         break;
+
+      case PNG_CHUNK_IEND:
+         if (     !(rpng->flags & RPNG_FLAG_HAS_IHDR) 
+               || !(rpng->flags & RPNG_FLAG_HAS_IDAT))
+            return false;
+
+         rpng->flags         |= RPNG_FLAG_HAS_IEND;
+         return false;
+   }
+
+   rpng->buff_data += chunk_size + 12;
+
+   /* Check whether data buffer pointer is valid */
+   if (rpng->buff_data > rpng->buff_end)
+      return false;
+   return true;
+}
+
+int rpng_process_image(rpng_t *rpng,
+      void **_data, size_t size, unsigned *width, unsigned *height)
+{
+   uint32_t **data = (uint32_t**)_data;
+
+   if (!rpng->process)
+   {
+      struct rpng_process *process = rpng_process_init(rpng);
+
+      if (!process)
+         goto error;
+
+      rpng->process = process;
+      return IMAGE_PROCESS_NEXT;
+   }
+
+   if (!(rpng->process->flags & RPNG_PROCESS_FLAG_INFLATE_INITIALIZED))
+   {
+      if (rpng_load_image_argb_process_inflate_init(rpng, data) == -1)
+         goto error;
+      return IMAGE_PROCESS_NEXT;
+   }
+
+   *width  = rpng->ihdr.width;
+   *height = rpng->ihdr.height;
+
+   if (rpng->ihdr.interlace && rpng->process)
+      return rpng_reverse_filter_adam7(data, &rpng->ihdr, rpng->process);
+   return rpng_reverse_filter_regular_iterate(data, &rpng->ihdr, rpng->process);
+
+error:
+   if (rpng->process)
+   {
+      if (rpng->process->inflate_buf)
+         free(rpng->process->inflate_buf);
+      if (rpng->process->stream)
+         rpng->process->stream_backend->stream_free(rpng->process->stream);
+      free(rpng->process);
+      rpng->process = NULL;
+   }
+   return IMAGE_PROCESS_ERROR;
+}
+
+void rpng_free(rpng_t *rpng)
+{
+   if (!rpng)
+      return;
+
+   if (rpng->idat_buf.data)
+      free(rpng->idat_buf.data);
+   if (rpng->process)
+   {
+      if (rpng->process->inflate_buf)
+         free(rpng->process->inflate_buf);
+      if (rpng->process->stream)
+      {
+         if (rpng->process->stream_backend && rpng->process->stream_backend->stream_free)
+            rpng->process->stream_backend->stream_free(rpng->process->stream);
+         else
+            free(rpng->process->stream);
+      }
+      free(rpng->process);
+   }
+
+   free(rpng);
+}
+
+bool rpng_start(rpng_t *rpng)
+{
+   if (!rpng)
+      return false;
+
+   /* Check whether reading the header will overflow
+    * the data buffer */
+   if (rpng->buff_end - rpng->buff_data < 8)
+      return false;
+
+   if (string_is_not_equal_fast(
+            rpng->buff_data, png_magic, sizeof(png_magic)))
+      return false;
+
+   rpng->buff_data += 8;
+
+   return true;
+}
+
+/**
+ * rpng_is_valid:
+ *
+ * Check if @rpng is a valid PNG image.
+ * Must contain an IHDR chunk, one or more IDAT
+ * chunks, and an IEND chunk.
+ *
+ * Leaf function.
+ *
+ * @return true if it's a valid PNG image, otherwise false.
+ **/
+bool rpng_is_valid(rpng_t *rpng)
+{
+   return (rpng && ((rpng->flags & (RPNG_FLAG_HAS_IHDR | RPNG_FLAG_HAS_IDAT |
+RPNG_FLAG_HAS_IEND)) > 0));
+}
+
+bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len)
+{
+   if (!rpng || (len < 1))
+      return false;
+
+   rpng->buff_data = (uint8_t*)data;
+   rpng->buff_end  = rpng->buff_data + (len - 1);
+
+   return true;
+}
+
+rpng_t *rpng_alloc(void)
+{
+   rpng_t *rpng = (rpng_t*)calloc(1, sizeof(*rpng));
+   if (!rpng)
+      return NULL;
+   return rpng;
+}
diff --git a/deps/libretro-common/formats/png/rpng_encode.c b/deps/libretro-common/formats/png/rpng_encode.c
new file mode 100644 (file)
index 0000000..ced535c
--- /dev/null
@@ -0,0 +1,448 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rpng_encode.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libretro.h>
+#include <encodings/crc32.h>
+#include <streams/interface_stream.h>
+#include <streams/trans_stream.h>
+
+#include "rpng_internal.h"
+
+#undef GOTO_END_ERROR
+#define GOTO_END_ERROR() do { \
+   fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__); \
+   ret = false; \
+   goto end; \
+} while (0)
+
+double DEFLATE_PADDING = 1.1;
+int PNG_ROUGH_HEADER = 100;
+
+static void dword_write_be(uint8_t *buf, uint32_t val)
+{
+   *buf++ = (uint8_t)(val >> 24);
+   *buf++ = (uint8_t)(val >> 16);
+   *buf++ = (uint8_t)(val >>  8);
+   *buf++ = (uint8_t)(val >>  0);
+}
+
+static bool png_write_crc_string(intfstream_t *intf_s, const uint8_t *data, size_t size)
+{
+   uint8_t crc_raw[4] = {0};
+   uint32_t crc       = encoding_crc32(0, data, size);
+
+   dword_write_be(crc_raw, crc);
+   return intfstream_write(intf_s, crc_raw, sizeof(crc_raw)) == sizeof(crc_raw);
+}
+
+static bool png_write_ihdr_string(intfstream_t *intf_s, const struct png_ihdr *ihdr)
+{
+   uint8_t ihdr_raw[21];
+
+   ihdr_raw[0]  = '0';                 /* Size */
+   ihdr_raw[1]  = '0';
+   ihdr_raw[2]  = '0';
+   ihdr_raw[3]  = '0';
+   ihdr_raw[4]  = 'I';
+   ihdr_raw[5]  = 'H';
+   ihdr_raw[6]  = 'D';
+   ihdr_raw[7]  = 'R';
+   ihdr_raw[8]  =   0;                 /* Width */
+   ihdr_raw[9]  =   0;
+   ihdr_raw[10] =   0;
+   ihdr_raw[11] =   0;
+   ihdr_raw[12] =   0;                 /* Height */
+   ihdr_raw[13] =   0;
+   ihdr_raw[14] =   0;
+   ihdr_raw[15] =   0;
+   ihdr_raw[16] =   ihdr->depth;       /* Depth */
+   ihdr_raw[17] =   ihdr->color_type;
+   ihdr_raw[18] =   ihdr->compression;
+   ihdr_raw[19] =   ihdr->filter;
+   ihdr_raw[20] =   ihdr->interlace;
+
+   dword_write_be(ihdr_raw +  0, sizeof(ihdr_raw) - 8);
+   dword_write_be(ihdr_raw +  8, ihdr->width);
+   dword_write_be(ihdr_raw + 12, ihdr->height);
+   if (intfstream_write(intf_s, ihdr_raw, sizeof(ihdr_raw)) != sizeof(ihdr_raw))
+      return false;
+
+   return png_write_crc_string(intf_s, ihdr_raw + sizeof(uint32_t),
+         sizeof(ihdr_raw) - sizeof(uint32_t));
+}
+
+static bool png_write_idat_string(intfstream_t* intf_s, const uint8_t *data, size_t size)
+{
+   if (intfstream_write(intf_s, data, size) != (ssize_t)size)
+      return false;
+
+   return png_write_crc_string(intf_s, data + sizeof(uint32_t), size - sizeof(uint32_t));
+}
+
+static bool png_write_iend_string(intfstream_t* intf_s)
+{
+   const uint8_t data[] = {
+      0, 0, 0, 0,
+      'I', 'E', 'N', 'D',
+   };
+
+   if (intfstream_write(intf_s, data, sizeof(data)) != sizeof(data))
+      return false;
+
+   return png_write_crc_string(intf_s, data + sizeof(uint32_t),
+         sizeof(data) - sizeof(uint32_t));
+}
+
+static void copy_argb_line(uint8_t *dst, const uint32_t *src, unsigned width)
+{
+   unsigned i;
+   for (i = 0; i < width; i++)
+   {
+      uint32_t col = src[i];
+      *dst++ = (uint8_t)(col >> 16);
+      *dst++ = (uint8_t)(col >>  8);
+      *dst++ = (uint8_t)(col >>  0);
+      *dst++ = (uint8_t)(col >> 24);
+   }
+}
+
+static void copy_bgr24_line(uint8_t *dst, const uint8_t *src, unsigned width)
+{
+   unsigned i;
+   for (i = 0; i < width; i++, dst += 3, src += 3)
+   {
+      dst[2] = src[0];
+      dst[1] = src[1];
+      dst[0] = src[2];
+   }
+}
+
+static unsigned count_sad(const uint8_t *data, size_t size)
+{
+   size_t i;
+   unsigned cnt = 0;
+   for (i = 0; i < size; i++)
+   {
+      if (data[i])
+         cnt += abs((int8_t)data[i]);
+   }
+   return cnt;
+}
+
+static unsigned filter_up(uint8_t *target, const uint8_t *line,
+      const uint8_t *prev, unsigned width, unsigned bpp)
+{
+   unsigned i;
+   width *= bpp;
+   for (i = 0; i < width; i++)
+      target[i] = line[i] - prev[i];
+
+   return count_sad(target, width);
+}
+
+static unsigned filter_sub(uint8_t *target, const uint8_t *line,
+      unsigned width, unsigned bpp)
+{
+   unsigned i;
+   width *= bpp;
+   for (i = 0; i < bpp; i++)
+      target[i] = line[i];
+   for (i = bpp; i < width; i++)
+      target[i] = line[i] - line[i - bpp];
+
+   return count_sad(target, width);
+}
+
+static unsigned filter_avg(uint8_t *target, const uint8_t *line,
+      const uint8_t *prev, unsigned width, unsigned bpp)
+{
+   unsigned i;
+   width *= bpp;
+   for (i = 0; i < bpp; i++)
+      target[i] = line[i] - (prev[i] >> 1);
+   for (i = bpp; i < width; i++)
+      target[i] = line[i] - ((line[i - bpp] + prev[i]) >> 1);
+
+   return count_sad(target, width);
+}
+
+static unsigned filter_paeth(uint8_t *target,
+      const uint8_t *line, const uint8_t *prev,
+      unsigned width, unsigned bpp)
+{
+   unsigned i;
+   width *= bpp;
+   for (i = 0; i < bpp; i++)
+      target[i] = line[i] - paeth(0, prev[i], 0);
+   for (i = bpp; i < width; i++)
+      target[i] = line[i] - paeth(line[i - bpp], prev[i], prev[i - bpp]);
+
+   return count_sad(target, width);
+}
+
+bool rpng_save_image_stream(const uint8_t *data, intfstream_t* intf_s,
+      unsigned width, unsigned height, signed pitch, unsigned bpp)
+{
+   unsigned h;
+   struct png_ihdr ihdr = {0};
+   bool ret = true;
+   const struct trans_stream_backend *stream_backend = NULL;
+   size_t encode_buf_size  = 0;
+   uint8_t *encode_buf     = NULL;
+   uint8_t *deflate_buf    = NULL;
+   uint8_t *rgba_line      = NULL;
+   uint8_t *up_filtered    = NULL;
+   uint8_t *sub_filtered   = NULL;
+   uint8_t *avg_filtered   = NULL;
+   uint8_t *paeth_filtered = NULL;
+   uint8_t *prev_encoded   = NULL;
+   uint8_t *encode_target  = NULL;
+   void *stream            = NULL;
+   uint32_t total_in       = 0;
+   uint32_t total_out      = 0;
+   
+   if (!intf_s)
+      GOTO_END_ERROR();
+
+   stream_backend = trans_stream_get_zlib_deflate_backend();
+
+   if (intfstream_write(intf_s, png_magic, sizeof(png_magic)) != sizeof(png_magic))
+      GOTO_END_ERROR();
+
+   ihdr.width = width;
+   ihdr.height = height;
+   ihdr.depth = 8;
+   ihdr.color_type = bpp == sizeof(uint32_t) ? 6 : 2; /* RGBA or RGB */
+   if (!png_write_ihdr_string(intf_s, &ihdr))
+      GOTO_END_ERROR();
+
+   encode_buf_size = (width * bpp + 1) * height;
+   encode_buf      = (uint8_t*)malloc(encode_buf_size);
+   if (!encode_buf)
+      GOTO_END_ERROR();
+
+   prev_encoded = (uint8_t*)calloc(1, width * bpp);
+   if (!prev_encoded)
+      GOTO_END_ERROR();
+
+   rgba_line      = (uint8_t*)malloc(width * bpp);
+   up_filtered    = (uint8_t*)malloc(width * bpp);
+   sub_filtered   = (uint8_t*)malloc(width * bpp);
+   avg_filtered   = (uint8_t*)malloc(width * bpp);
+   paeth_filtered = (uint8_t*)malloc(width * bpp);
+   if (!rgba_line || !up_filtered || !sub_filtered || !avg_filtered || !paeth_filtered)
+      GOTO_END_ERROR();
+
+   encode_target = encode_buf;
+   for (h = 0; h < height;
+         h++, encode_target += width * bpp, data += pitch)
+   {
+      if (bpp == sizeof(uint32_t))
+         copy_argb_line(rgba_line, (const uint32_t*)data, width);
+      else
+         copy_bgr24_line(rgba_line, data, width);
+
+      /* Try every filtering method, and choose the method
+       * which has most entries as zero.
+       *
+       * This is probably not very optimal, but it's very
+       * simple to implement.
+       */
+      {
+         unsigned none_score  = count_sad(rgba_line, width * bpp);
+         unsigned up_score    = filter_up(up_filtered, rgba_line, prev_encoded, width, bpp);
+         unsigned sub_score   = filter_sub(sub_filtered, rgba_line, width, bpp);
+         unsigned avg_score   = filter_avg(avg_filtered, rgba_line, prev_encoded, width, bpp);
+         unsigned paeth_score = filter_paeth(paeth_filtered, rgba_line, prev_encoded, width, bpp);
+
+         uint8_t filter       = 0;
+         unsigned min_sad     = none_score;
+         const uint8_t *chosen_filtered = rgba_line;
+
+         if (sub_score < min_sad)
+         {
+            filter = 1;
+            chosen_filtered = sub_filtered;
+            min_sad = sub_score;
+         }
+
+         if (up_score < min_sad)
+         {
+            filter = 2;
+            chosen_filtered = up_filtered;
+            min_sad = up_score;
+         }
+
+         if (avg_score < min_sad)
+         {
+            filter = 3;
+            chosen_filtered = avg_filtered;
+            min_sad = avg_score;
+         }
+
+         if (paeth_score < min_sad)
+         {
+            filter = 4;
+            chosen_filtered = paeth_filtered;
+         }
+
+         *encode_target++ = filter;
+         memcpy(encode_target, chosen_filtered, width * bpp);
+
+         memcpy(prev_encoded, rgba_line, width * bpp);
+      }
+   }
+
+   deflate_buf = (uint8_t*)malloc(encode_buf_size * 2); /* Just to be sure. */
+   if (!deflate_buf)
+      GOTO_END_ERROR();
+
+   stream = stream_backend->stream_new();
+
+   if (!stream)
+      GOTO_END_ERROR();
+
+   stream_backend->set_in(
+         stream,
+         encode_buf,
+         (unsigned)encode_buf_size);
+   stream_backend->set_out(
+         stream,
+         deflate_buf + 8,
+         (unsigned)(encode_buf_size * 2));
+
+   if (!stream_backend->trans(stream, true, &total_in, &total_out, NULL))
+      GOTO_END_ERROR();
+
+   memcpy(deflate_buf + 4, "IDAT", 4);
+   dword_write_be(deflate_buf + 0,        ((uint32_t)total_out));
+   if (!png_write_idat_string(intf_s, deflate_buf, ((size_t)total_out + 8)))
+      GOTO_END_ERROR();
+
+   if (!png_write_iend_string(intf_s))
+      GOTO_END_ERROR();
+end:
+   free(encode_buf);
+   free(deflate_buf);
+   free(rgba_line);
+   free(prev_encoded);
+   free(up_filtered);
+   free(sub_filtered);
+   free(avg_filtered);
+   free(paeth_filtered);
+
+   if (stream_backend)
+   {
+      if (stream)
+      {
+         if (stream_backend->stream_free)
+            stream_backend->stream_free(stream);
+      }
+   }
+   return ret;
+}
+
+bool rpng_save_image_argb(const char *path, const uint32_t *data,
+      unsigned width, unsigned height, unsigned pitch)
+{
+   bool ret                      = false;
+   intfstream_t* intf_s          = NULL;
+   
+   intf_s = intfstream_open_file(path, 
+         RETRO_VFS_FILE_ACCESS_WRITE,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+   ret = rpng_save_image_stream((const uint8_t*) data, intf_s,
+                                width, height,
+                                (signed) pitch, sizeof(uint32_t));
+   intfstream_close(intf_s);
+   free(intf_s);
+   return ret;
+}
+
+bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
+      unsigned width, unsigned height, unsigned pitch)
+{
+   bool ret                      = false;
+   intfstream_t* intf_s          = NULL;
+   
+   intf_s = intfstream_open_file(path, 
+         RETRO_VFS_FILE_ACCESS_WRITE,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   ret = rpng_save_image_stream(data, intf_s, width, height, 
+                                (signed) pitch, 3);
+   intfstream_close(intf_s);
+   free(intf_s);
+   return ret;
+}
+
+
+uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
+      unsigned width, unsigned height, signed pitch, uint64_t* bytes)
+{
+   bool ret                    = false;
+   uint8_t* buf                = NULL;
+   uint8_t* output             = NULL;
+   int buf_length              = 0;
+   intfstream_t* intf_s        = NULL;
+
+   buf_length = (int)(width*height*3*DEFLATE_PADDING)+PNG_ROUGH_HEADER;
+   buf        = (uint8_t*)malloc(buf_length*sizeof(uint8_t));
+   if (!buf)
+      GOTO_END_ERROR(); 
+
+   intf_s = intfstream_open_writable_memory(buf, 
+         RETRO_VFS_FILE_ACCESS_WRITE,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE,
+         buf_length);
+
+   ret = rpng_save_image_stream((const uint8_t*)data, 
+            intf_s, width, height, pitch, 3);
+
+   *bytes = intfstream_get_ptr(intf_s);
+   intfstream_rewind(intf_s);
+   output = (uint8_t*)malloc((size_t)((*bytes)*sizeof(uint8_t)));
+   if (!output)
+      GOTO_END_ERROR();
+   intfstream_read(intf_s, output, *bytes);
+
+end:
+   if (buf)
+      free(buf);
+   if (intf_s)
+   {
+      intfstream_close(intf_s);
+      free(intf_s);
+   }
+   if (ret == false)
+   {
+      if (output)
+         free(output);
+      return NULL;
+   }
+   return output;
+}
+
diff --git a/deps/libretro-common/formats/png/rpng_internal.h b/deps/libretro-common/formats/png/rpng_internal.h
new file mode 100644 (file)
index 0000000..9e5d78f
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rpng_internal.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _RPNG_COMMON_H
+#define _RPNG_COMMON_H
+
+#include <stdint.h>
+#include <filters.h>
+#include <formats/rpng.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+static const uint8_t png_magic[8] = {
+   0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a,
+};
+
+struct png_ihdr
+{
+   uint32_t width;
+   uint32_t height;
+   uint8_t depth;
+   uint8_t color_type;
+   uint8_t compression;
+   uint8_t filter;
+   uint8_t interlace;
+};
+
+#endif
diff --git a/deps/libretro-common/formats/tga/rtga.c b/deps/libretro-common/formats/tga/rtga.c
new file mode 100644 (file)
index 0000000..01b96e3
--- /dev/null
@@ -0,0 +1,473 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rtga.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* Modified version of stb_image's TGA sources. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stddef.h> /* ptrdiff_t on osx */
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_inline.h>
+
+#include <formats/image.h>
+#include <formats/rtga.h>
+
+#define RTGA_COMPUTE_Y(r, g, b) ((uint8_t)((((r) * 77) + ((g) * 150) +  (29 * (b))) >> 8))
+
+struct rtga
+{
+   uint8_t *buff_data;
+   uint32_t *output_image;
+};
+
+typedef struct
+{
+   uint8_t *img_buffer;
+   uint8_t *img_buffer_end;
+   uint8_t *img_buffer_original;
+   int buflen;
+   int img_n, img_out_n;
+   uint32_t img_x, img_y;
+   uint8_t buffer_start[128];
+} rtga_context;
+
+static INLINE uint8_t rtga_get8(rtga_context *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+   return 0;
+}
+
+static void rtga_skip(rtga_context *s, int n)
+{
+   if (n < 0)
+   {
+      s->img_buffer = s->img_buffer_end;
+      return;
+   }
+   s->img_buffer += n;
+}
+
+static int rtga_get16le(rtga_context *s)
+{
+   return rtga_get8(s) + (rtga_get8(s) << 8);
+}
+
+static unsigned char *rtga_convert_format(
+      unsigned char *data,
+      int img_n,
+      int req_comp,
+      unsigned int x,
+      unsigned int y)
+{
+   int i,j;
+   unsigned char *good = (unsigned char *) malloc(req_comp * x * y);
+
+   if (!good)
+   {
+      free(data);
+      return NULL;
+   }
+
+   for (j=0; j < (int) y; ++j)
+   {
+      unsigned char *src  = data + j * x * img_n   ;
+      unsigned char *dest = good + j * x * req_comp;
+
+      switch (((img_n)*8+(req_comp)))
+      {
+         case ((1)*8+(2)):
+            for (i=x-1; i >= 0; --i, src += 1, dest += 2)
+            {
+               dest[0]=src[0];
+               dest[1]=255;
+            }
+            break;
+         case ((1)*8+(3)):
+            for (i=x-1; i >= 0; --i, src += 1, dest += 3)
+               dest[0]=dest[1]=dest[2]=src[0];
+            break;
+         case ((1)*8+(4)):
+            for (i=x-1; i >= 0; --i, src += 1, dest += 4)
+            {
+               dest[0]=dest[1]=dest[2]=src[0];
+               dest[3]=255;
+            }
+            break;
+         case ((2)*8+(1)):
+            for (i=x-1; i >= 0; --i, src += 2, dest += 1)
+               dest[0]=src[0];
+            break;
+         case ((2)*8+(3)):
+            for (i=x-1; i >= 0; --i, src += 2, dest += 3)
+               dest[0]=dest[1]=dest[2]=src[0];
+            break;
+         case ((2)*8+(4)):
+            for (i=x-1; i >= 0; --i, src += 2, dest += 4)
+            {
+               dest[0]=dest[1]=dest[2]=src[0];
+               dest[3]=src[1];
+            }
+            break;
+         case ((3)*8+(4)):
+            for (i=x-1; i >= 0; --i, src += 3, dest += 4)
+            {
+               dest[0]=src[0];
+               dest[1]=src[1];
+               dest[2]=src[2];
+               dest[3]=255;
+            }
+            break;
+         case ((3)*8+(1)):
+            for (i=x-1; i >= 0; --i, src += 3, dest += 1)
+               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
+            break;
+         case ((3)*8+(2)):
+            for (i=x-1; i >= 0; --i, src += 3, dest += 2)
+            {
+               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
+               dest[1] = 255;
+            }
+            break;
+         case ((4)*8+(1)):
+            for (i=x-1; i >= 0; --i, src += 4, dest += 1)
+               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
+            break;
+         case ((4)*8+(2)):
+            for (i=x-1; i >= 0; --i, src += 4, dest += 2)
+            {
+               dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
+               dest[1] = src[3];
+            }
+            break;
+         case ((4)*8+(3)):
+            for (i=x-1; i >= 0; --i, src += 4, dest += 3)
+            {
+               dest[0]=src[0];
+               dest[1]=src[1];
+               dest[2]=src[2];
+            }
+            break;
+         default:
+            break;
+      }
+   }
+
+   free(data);
+   return good;
+}
+
+static uint8_t *rtga_tga_load(rtga_context *s,
+      unsigned *x, unsigned *y, int *comp, int req_comp)
+{
+   /* Read in the TGA header stuff */
+   int tga_offset          = rtga_get8(s);
+   int tga_indexed         = rtga_get8(s);
+   int tga_image_type      = rtga_get8(s);
+   int tga_is_RLE          = 0;
+   int tga_palette_start   = rtga_get16le(s);
+   int tga_palette_len     = rtga_get16le(s);
+   int tga_palette_bits    = rtga_get8(s);
+   int tga_x_origin        = rtga_get16le(s);
+   int tga_y_origin        = rtga_get16le(s);
+   int tga_width           = rtga_get16le(s);
+   int tga_height          = rtga_get16le(s);
+   int tga_bits_per_pixel  = rtga_get8(s);
+   int tga_comp            = tga_bits_per_pixel / 8;
+   int tga_inverted        = rtga_get8(s);
+
+   /*   image data */
+   unsigned char *tga_data = NULL;
+
+   (void)tga_palette_start;
+   (void)tga_x_origin;
+   (void)tga_y_origin;
+
+   /*   do a tiny bit of precessing */
+   if (tga_image_type >= 8)
+   {
+      tga_image_type -= 8;
+      tga_is_RLE = 1;
+   }
+
+   /* int tga_alpha_bits = tga_inverted & 15; */
+   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+   /*   error check */
+   if (
+         (tga_width < 1) || (tga_height < 1) ||
+         (tga_image_type < 1) || (tga_image_type > 3) ||
+         (
+          (tga_bits_per_pixel != 8)  && (tga_bits_per_pixel != 16) &&
+          (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)
+         )
+      )
+      return NULL; /* we don't report this as a bad TGA because we don't even know if it's TGA */
+
+   /*   If paletted, then we will use the number of bits from the palette */
+   if (tga_indexed)
+      tga_comp = tga_palette_bits / 8;
+
+   /*   TGA info */
+   *x = tga_width;
+   *y = tga_height;
+   if (comp)
+      *comp = tga_comp;
+
+   tga_data = (unsigned char*)malloc((size_t)tga_width * tga_height * tga_comp);
+   if (!tga_data)
+      return NULL;
+
+   /* skip to the data's starting position (offset usually = 0) */
+   rtga_skip(s, tga_offset );
+
+   if (!tga_indexed && !tga_is_RLE)
+   {
+      int i;
+      for (i=0; i < tga_height; ++i)
+      {
+         int _y           = tga_inverted ? (tga_height -i - 1) : i;
+         uint8_t *tga_row = tga_data + _y * tga_width * tga_comp;
+         int n            = tga_width * tga_comp;
+
+         if (s->img_buffer + n <= s->img_buffer_end)
+         {
+            memcpy(tga_row, s->img_buffer, n);
+            s->img_buffer += n;
+         }
+      }
+   }
+   else
+   {
+      int i, j;
+      int RLE_repeating          = 0;
+      int RLE_count              = 0;
+      int read_next_pixel        = 1;
+      /* Needs to be at least 33 bytes to silence a GCC warning,
+       * only 4 are actually used */
+      unsigned char raw_data[33] = {0};
+      unsigned char *tga_palette = NULL;
+
+      /*   Do I need to load a palette? */
+      if (tga_indexed)
+      {
+         int n;
+         /* Any data to skip? (offset usually = 0) */
+         rtga_skip(s, tga_palette_start );
+         /* Load the palette */
+         tga_palette = (unsigned char*)malloc(tga_palette_len * tga_palette_bits / 8);
+
+         if (!tga_palette)
+         {
+            free(tga_data);
+            return NULL;
+         }
+
+         n = tga_palette_len * tga_palette_bits / 8;
+
+         if (s->img_buffer+n <= s->img_buffer_end)
+         {
+            memcpy(tga_palette, s->img_buffer, n);
+            s->img_buffer += n;
+         }
+         else
+         {
+            free(tga_data);
+            free(tga_palette);
+            return NULL;
+         }
+      }
+
+      /*   load the data */
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         /*   if I'm in RLE mode, do I need to get a RLE rtga_png chunk? */
+         if (tga_is_RLE)
+         {
+            if (RLE_count == 0)
+            {
+               /*   yep, get the next byte as a RLE command */
+               int RLE_cmd     = rtga_get8(s);
+               RLE_count       = 1 + (RLE_cmd & 127);
+               RLE_repeating   = RLE_cmd >> 7;
+               read_next_pixel = 1;
+            }
+            else if (!RLE_repeating)
+               read_next_pixel = 1;
+         }
+         else
+            read_next_pixel = 1;
+
+         /*   OK, if I need to read a pixel, do it now */
+         if (read_next_pixel)
+         {
+            /*   load however much data we did have */
+            if (tga_indexed)
+            {
+               /*   read in 1 byte, then perform the lookup */
+               int pal_idx = rtga_get8(s);
+               if (pal_idx >= tga_palette_len) /* invalid index */
+                  pal_idx = 0;
+               pal_idx *= tga_bits_per_pixel / 8;
+               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+                  raw_data[j] = tga_palette[pal_idx+j];
+            }
+            else
+            {
+               /* read in the data raw */
+               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+                  raw_data[j] = rtga_get8(s);
+            }
+
+            /*   clear the reading flag for the next pixel */
+            read_next_pixel = 0;
+         } /* end of reading a pixel */
+
+         /* copy data */
+         for (j = 0; j < tga_comp; ++j)
+            tga_data[i*tga_comp+j] = raw_data[j];
+
+         /*   in case we're in RLE mode, keep counting down */
+         --RLE_count;
+      }
+
+      /*   do I need to invert the image? */
+      if (tga_inverted)
+      {
+         if (tga_data)
+         {
+            for (j = 0; j*2 < tga_height; ++j)
+            {
+               int index1 = j * tga_width * tga_comp;
+               int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+
+               for (i = tga_width * tga_comp; i > 0; --i)
+               {
+                  unsigned char temp = tga_data[index1];
+                  tga_data[index1]   = tga_data[index2];
+                  tga_data[index2]   = temp;
+                  ++index1;
+                  ++index2;
+               }
+            }
+         }
+      }
+
+      /* Clear my palette, if I had one */
+      if (tga_palette)
+         free(tga_palette);
+   }
+
+   /* swap RGB */
+   if (tga_comp >= 3)
+   {
+      int i;
+      unsigned char* tga_pixel = tga_data;
+
+      for (i = 0; i < tga_width * tga_height; ++i)
+      {
+         unsigned char temp  = tga_pixel[0];
+         tga_pixel[0]        = tga_pixel[2];
+         tga_pixel[2]        = temp;
+         tga_pixel          += tga_comp;
+      }
+   }
+
+   /* convert to target component count */
+   if (     (req_comp)
+         && (req_comp >= 1 && req_comp <= 4)
+         && (req_comp != tga_comp))
+   {
+      tga_data = rtga_convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+   }
+
+   return tga_data;
+}
+
+static uint8_t *rtga_load_from_memory(uint8_t const *buffer, int len,
+      unsigned *x, unsigned *y, int *comp, int req_comp)
+{
+   rtga_context s;
+
+   s.img_buffer          = (uint8_t *)buffer;
+   s.img_buffer_original = (uint8_t *) buffer;
+   s.img_buffer_end      = (uint8_t *) buffer+len;
+
+   return rtga_tga_load(&s,x,y,comp,req_comp);
+}
+
+int rtga_process_image(rtga_t *rtga, void **buf_data,
+      size_t size, unsigned *width, unsigned *height)
+{
+   int comp;
+   unsigned size_tex     = 0;
+
+   if (!rtga)
+      return IMAGE_PROCESS_ERROR;
+
+   rtga->output_image   = (uint32_t*)rtga_load_from_memory(rtga->buff_data,
+                           (int)size, width, height, &comp, 4);
+   *buf_data             = rtga->output_image;
+   size_tex              = (*width) * (*height);
+
+   /* Convert RGBA to ARGB */
+   while (size_tex--)
+   {
+      unsigned int texel = rtga->output_image[size_tex];
+      unsigned int A     = texel & 0xFF000000;
+      unsigned int B     = texel & 0x00FF0000;
+      unsigned int G     = texel & 0x0000FF00;
+      unsigned int R     = texel & 0x000000FF;
+      ((unsigned int*)rtga->output_image)[size_tex] = A | (R << 16) | G | (B >> 16);
+   };
+
+   return IMAGE_PROCESS_END;
+}
+
+bool rtga_set_buf_ptr(rtga_t *rtga, void *data)
+{
+   if (!rtga)
+      return false;
+
+   rtga->buff_data = (uint8_t*)data;
+
+   return true;
+}
+
+void rtga_free(rtga_t *rtga)
+{
+   if (!rtga)
+      return;
+
+   free(rtga);
+}
+
+rtga_t *rtga_alloc(void)
+{
+   rtga_t *rtga = (rtga_t*)calloc(1, sizeof(*rtga));
+   if (!rtga)
+      return NULL;
+   return rtga;
+}
diff --git a/deps/libretro-common/formats/wav/rwav.c b/deps/libretro-common/formats/wav/rwav.c
new file mode 100644 (file)
index 0000000..b9ed71b
--- /dev/null
@@ -0,0 +1,187 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rwav.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stddef.h> /* ptrdiff_t on osx */
+#include <stdlib.h>
+#include <string.h>
+
+#include <formats/rwav.h>
+
+enum
+{
+   ITER_BEGIN,
+   ITER_COPY_SAMPLES,
+   ITER_COPY_SAMPLES_8,
+   ITER_COPY_SAMPLES_16
+};
+
+struct rwav_iterator
+{
+   rwav_t *out;
+   const uint8_t *data;
+   size_t size;
+   size_t i, j;
+   int step;
+};
+
+void rwav_init(rwav_iterator_t* iter, rwav_t* out, const void* buf, size_t size)
+{
+   iter->out    = out;
+   iter->data   = (const uint8_t*)buf;
+   iter->size   = size;
+   iter->step   = ITER_BEGIN;
+
+   out->samples = NULL;
+}
+
+enum rwav_state rwav_iterate(rwav_iterator_t *iter)
+{
+   size_t s;
+   uint16_t *u16       = NULL;
+   void *samples       = NULL;
+   rwav_t *rwav        = iter->out;
+   const uint8_t *data = iter->data;
+
+   switch (iter->step)
+   {
+      case ITER_BEGIN:
+         if (iter->size < 44)
+            return RWAV_ITERATE_ERROR; /* buffer is smaller than an empty wave file */
+
+         if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F')
+            return RWAV_ITERATE_ERROR;
+
+         if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E')
+            return RWAV_ITERATE_ERROR;
+
+         if (data[12] != 'f' || data[13] != 'm' || data[14] != 't' || data[15] != ' ')
+            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */
+
+         if (data[16] != 16 || data[17] != 0 || data[18] != 0 || data[19] != 0)
+            return RWAV_ITERATE_ERROR;
+
+         if (data[20] != 1 || data[21] != 0)
+            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */
+
+         if (data[36] != 'd' || data[37] != 'a' || data[38] != 't' || data[39] != 'a')
+            return RWAV_ITERATE_ERROR;
+
+         rwav->bitspersample = data[34] | data[35] << 8;
+
+         if (rwav->bitspersample != 8 && rwav->bitspersample != 16)
+            return RWAV_ITERATE_ERROR; /* we only support 8 and 16 bps */
+
+         rwav->subchunk2size = data[40] | data[41] << 8 | data[42] << 16 | data[43] << 24;
+
+         if ((rwav->subchunk2size < 1) ||
+             (rwav->subchunk2size > iter->size - 44))
+            return RWAV_ITERATE_ERROR; /* too few bytes in buffer */
+
+         samples = malloc(rwav->subchunk2size);
+
+         if (!samples)
+            return RWAV_ITERATE_ERROR;
+
+         rwav->numchannels = data[22] | data[23] << 8;
+         rwav->numsamples  = rwav->subchunk2size * 8 / rwav->bitspersample / rwav->numchannels;
+         rwav->samplerate  = data[24] | data[25] << 8 | data[26] << 16 | data[27] << 24;
+         rwav->samples     = samples;
+
+         iter->step = ITER_COPY_SAMPLES;
+         return RWAV_ITERATE_MORE;
+
+      case ITER_COPY_SAMPLES:
+         iter->i = 0;
+
+         if (rwav->bitspersample == 8)
+         {
+            iter->step = ITER_COPY_SAMPLES_8;
+
+            /* TODO/FIXME - what is going on here? */
+            case ITER_COPY_SAMPLES_8:
+            s = rwav->subchunk2size - iter->i;
+
+            if (s > RWAV_ITERATE_BUF_SIZE)
+               s = RWAV_ITERATE_BUF_SIZE;
+
+            memcpy((void*)((uint8_t*)rwav->samples + iter->i), (void *)(iter->data + 44 + iter->i), s);
+            iter->i += s;
+         }
+         else
+         {
+            iter->step = ITER_COPY_SAMPLES_16;
+            iter->j    = 0;
+
+            /* TODO/FIXME - what is going on here? */
+            case ITER_COPY_SAMPLES_16:
+            s = rwav->subchunk2size - iter->i;
+
+            if (s > RWAV_ITERATE_BUF_SIZE)
+               s = RWAV_ITERATE_BUF_SIZE;
+
+            u16 = (uint16_t *)rwav->samples;
+
+            while (s != 0)
+            {
+               u16[iter->j++] = iter->data[44 + iter->i] | iter->data[45 + iter->i] << 8;
+               iter->i += 2;
+               s -= 2;
+            }
+         }
+
+         if (iter->i < rwav->subchunk2size)
+            return RWAV_ITERATE_MORE;
+         return RWAV_ITERATE_DONE;
+   }
+
+   return RWAV_ITERATE_ERROR;
+}
+
+enum rwav_state rwav_load(rwav_t* out, const void* buf, size_t size)
+{
+   enum rwav_state res;
+   rwav_iterator_t iter;
+
+   iter.out             = NULL;
+   iter.data            = NULL;
+   iter.size            = 0;
+   iter.i               = 0;
+   iter.j               = 0;
+   iter.step            = 0;
+
+   rwav_init(&iter, out, buf, size);
+
+   do
+   {
+      res = rwav_iterate(&iter);
+   }while (res == RWAV_ITERATE_MORE);
+
+   return res;
+}
+
+void rwav_free(rwav_t *rwav)
+{
+   free((void*)rwav->samples);
+}
diff --git a/deps/libretro-common/formats/xml/rxml.c b/deps/libretro-common/formats/xml/rxml.c
new file mode 100644 (file)
index 0000000..cce1040
--- /dev/null
@@ -0,0 +1,321 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rxml.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <boolean.h>
+#include <streams/file_stream.h>
+#include <compat/posix_string.h>
+#include <string/stdstring.h>
+
+#include <formats/rxml.h>
+
+#include "../../deps/yxml/yxml.h"
+
+#define BUFSIZE 4096
+
+struct rxml_parse_buffer
+{
+   rxml_node_t *stack[32];
+   char xml[BUFSIZE];
+   char val[BUFSIZE];
+};
+
+struct rxml_document
+{
+   struct rxml_node *root_node;
+};
+
+struct rxml_node *rxml_root_node(rxml_document_t *doc)
+{
+   if (doc)
+      return doc->root_node;
+   return NULL;
+}
+
+static void rxml_free_node(struct rxml_node *node)
+{
+   struct rxml_node *head = NULL;
+   struct rxml_attrib_node *attrib_node_head = NULL;
+
+   if (!node)
+      return;
+
+   for (head = node->children; head; )
+   {
+      struct rxml_node *next_node = (struct rxml_node*)head->next;
+      rxml_free_node(head);
+      head = next_node;
+   }
+
+   for (attrib_node_head = node->attrib; attrib_node_head; )
+   {
+      struct rxml_attrib_node *next_attrib =
+            (struct rxml_attrib_node*)attrib_node_head->next;
+
+      if (attrib_node_head->attrib)
+         free(attrib_node_head->attrib);
+      if (attrib_node_head->value)
+         free(attrib_node_head->value);
+      if (attrib_node_head)
+         free(attrib_node_head);
+
+      attrib_node_head = next_attrib;
+   }
+
+   if (node->name)
+      free(node->name);
+   if (node->data)
+      free(node->data);
+   if (node)
+      free(node);
+}
+
+rxml_document_t *rxml_load_document(const char *path)
+{
+   rxml_document_t *doc    = NULL;
+   char *memory_buffer     = NULL;
+   int64_t len             = 0;
+   RFILE *file             = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   if (!file)
+      return NULL;
+
+   len                     = filestream_get_size(file);
+   memory_buffer           = (char*)malloc((size_t)(len + 1));
+   if (!memory_buffer)
+      goto error;
+
+   memory_buffer[len]      = '\0';
+   if (filestream_read(file, memory_buffer, len) != len)
+      goto error;
+
+   filestream_close(file);
+   file                    = NULL;
+
+   doc                     = rxml_load_document_string(memory_buffer);
+
+   free(memory_buffer);
+   return doc;
+
+error:
+   free(memory_buffer);
+   if (file)
+      filestream_close(file);
+   return NULL;
+}
+
+rxml_document_t *rxml_load_document_string(const char *str)
+{
+   yxml_t x;
+   rxml_document_t *doc          = NULL;
+   size_t stack_i                = 0;
+   size_t level                  = 0;
+   int i                         = 0;
+   char *valptr                  = NULL;
+   rxml_node_t *node             = NULL;
+   struct rxml_attrib_node *attr = NULL;
+   struct rxml_parse_buffer *buf = (struct rxml_parse_buffer*)
+      malloc(sizeof(*buf));
+   if (!buf)
+      return NULL;
+
+   valptr                        = buf->val;
+   doc                           = (rxml_document_t*)malloc(sizeof(*doc));
+   if (!doc)
+      goto error;
+
+   yxml_init(&x, buf->xml, BUFSIZE);
+
+   for (; *str; ++str)
+   {
+      yxml_ret_t r = yxml_parse(&x, *str);
+
+      if (r < 0)
+         goto error;
+
+      switch (r)
+      {
+
+         case YXML_ELEMSTART:
+            if (node)
+            {
+               if (level > stack_i)
+               {
+                  buf->stack[stack_i]      = node;
+                  ++stack_i;
+
+                  node->children           = (rxml_node_t*)
+                     malloc(sizeof(*node));
+
+                  node->children->name     = NULL;
+                  node->children->data     = NULL;
+                  node->children->attrib   = NULL;
+                  node->children->children = NULL;
+                  node->children->next     = NULL;
+
+                  node                     = node->children;
+               }
+               else
+               {
+                  node->next               = (rxml_node_t*)
+                     malloc(sizeof(*node));
+
+                  node->next->name         = NULL;
+                  node->next->data         = NULL;
+                  node->next->attrib       = NULL;
+                  node->next->children     = NULL;
+                  node->next->next         = NULL;
+
+                  node                     = node->next;
+               }
+            }
+            else
+               node = doc->root_node       = (rxml_node_t*)
+                  calloc(1, sizeof(*node));
+
+            if (node->name)
+               free(node->name);
+            node->name                     = strdup(x.elem);
+
+            attr                           = NULL;
+            valptr                         = buf->val;
+
+            ++level;
+            break;
+
+         case YXML_ELEMEND:
+            --level;
+
+            if (valptr > buf->val)
+            {
+               *valptr = '\0';
+
+               /* Original code was broken here:
+                * > If an element ended on two successive
+                *   iterations, on the second iteration
+                *   the 'data' for the *previous* node would
+                *   get overwritten
+                * > This effectively erased the data for the
+                *   previous node, *and* caused a memory leak
+                *   (due to the double strdup())
+                * It seems the correct thing to do here is
+                * only copy the data if the current 'level'
+                * and 'stack index' are the same... */
+               if (level == stack_i)
+               {
+                  if (node->data)
+                     free(node->data);
+                  node->data = strdup(buf->val);
+               }
+
+               valptr = buf->val;
+            }
+
+            if (level < stack_i)
+            {
+               --stack_i;
+               node = buf->stack[stack_i];
+            }
+            break;
+
+         case YXML_CONTENT:
+            for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
+            {
+               *valptr = x.data[i];
+               ++valptr;
+            }
+            break;
+
+         case YXML_ATTRSTART:
+            if (attr)
+               attr = attr->next   = (struct rxml_attrib_node*)
+                     calloc(1, sizeof(*attr));
+            else
+               attr = node->attrib = (struct rxml_attrib_node*)calloc(1, sizeof(*attr));
+
+            if (attr->attrib)
+               free(attr->attrib);
+            attr->attrib = strdup(x.attr);
+
+            valptr       = buf->val;
+            break;
+
+         case YXML_ATTRVAL:
+            for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
+            {
+               *valptr = x.data[i];
+               ++valptr;
+            }
+            break;
+
+         case YXML_ATTREND:
+            if (valptr > buf->val)
+            {
+               *valptr = '\0';
+
+               if (attr)
+               {
+                  if (attr->value)
+                     free(attr->value);
+                  attr->value = strdup(buf->val);
+               }
+
+               valptr      = buf->val;
+            }
+            break;
+
+         default:
+            break;
+      }
+   }
+
+   free(buf);
+   return doc;
+
+error:
+   rxml_free_document(doc);
+   free(buf);
+   return NULL;
+}
+
+void rxml_free_document(rxml_document_t *doc)
+{
+   if (!doc)
+      return;
+
+   if (doc->root_node)
+      rxml_free_node(doc->root_node);
+
+   free(doc);
+}
+
+const char *rxml_node_attrib(struct rxml_node *node, const char *attrib)
+{
+   struct rxml_attrib_node *attribs = NULL;
+   for (attribs = node->attrib; attribs; attribs = attribs->next)
+   {
+      if (string_is_equal(attrib, attribs->attrib))
+         return attribs->value;
+   }
+
+   return NULL;
+}
diff --git a/deps/libretro-common/formats/xml/test/Makefile b/deps/libretro-common/formats/xml/test/Makefile
new file mode 100644 (file)
index 0000000..021f3c0
--- /dev/null
@@ -0,0 +1,28 @@
+TARGET := rxml
+
+LIBRETRO_XML_DIR  := ..
+LIBRETRO_COMM_DIR := ../../..
+LIBRETRO_DEPS_DIR := ../../../../deps
+
+SOURCES := \
+       rxml_test.c \
+       $(LIBRETRO_XML_DIR)/rxml.c \
+       $(LIBRETRO_DEPS_DIR)/yxml/yxml.c \
+       $(LIBRETRO_COMM_DIR)/streams/file_stream.c
+
+OBJS := $(SOURCES:.c=.o)
+
+CFLAGS += -DRXML_TEST -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/formats/xml/test/rxml_test.c b/deps/libretro-common/formats/xml/test/rxml_test.c
new file mode 100644 (file)
index 0000000..2bd39c2
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright  (C) 2010-2018 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rxml_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <formats/rxml.h>
+#include <stdio.h>
+
+static void print_siblings(struct rxml_node *node, unsigned level)
+{
+   fprintf(stderr, "\n%*sName: %s\n", level * 4, "", node->name);
+   if (node->data)
+      fprintf(stderr, "%*sData: %s\n", level * 4, "", node->data);
+
+   for (const struct rxml_attrib_node *attrib =
+         node->attrib; attrib; attrib = attrib->next)
+      fprintf(stderr, "%*s  Attrib: %s = %s\n", level * 4, "",
+            attrib->attrib, attrib->value);
+
+   if (node->children)
+      print_siblings(node->children, level + 1);
+
+   if (node->next)
+      print_siblings(node->next, level);
+}
+
+static void rxml_log_document(const char *path)
+{
+   rxml_document_t *doc = rxml_load_document(path);
+   if (!doc)
+   {
+      fprintf(stderr, "rxml: Failed to load document: %s\n", path);
+      return;
+   }
+
+   print_siblings(rxml_root_node(doc), 0);
+   rxml_free_document(doc);
+}
+
+int main(int argc, char *argv[])
+{
+   if (argc != 2)
+   {
+      fprintf(stderr, "Usage: %s <path>\n", argv[0]);
+      return 1;
+   }
+
+   rxml_log_document(argv[1]);
+}
diff --git a/deps/libretro-common/gfx/gl_capabilities.c b/deps/libretro-common/gfx/gl_capabilities.c
new file mode 100644 (file)
index 0000000..f7e4838
--- /dev/null
@@ -0,0 +1,335 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (gl_capabilities.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <math.h>
+#include <string.h>
+
+#include <boolean.h>
+
+#include <glsym/glsym.h>
+
+#include <gfx/gl_capabilities.h>
+
+static bool gl_core_context       = false;
+
+bool gl_query_core_context_in_use(void)
+{
+   return gl_core_context;
+}
+
+void gl_query_core_context_set(bool set)
+{
+   gl_core_context     =  set;
+}
+
+void gl_query_core_context_unset(void)
+{
+   gl_core_context = false;
+}
+
+bool gl_query_extension(const char *ext)
+{
+   bool ret = false;
+
+   if (gl_query_core_context_in_use())
+   {
+#ifdef GL_NUM_EXTENSIONS
+      GLint i;
+      GLint exts = 0;
+      glGetIntegerv(GL_NUM_EXTENSIONS, &exts);
+      for (i = 0; i < exts; i++)
+      {
+         const char *str = (const char*)glGetStringi(GL_EXTENSIONS, i);
+         if (str && strstr(str, ext))
+         {
+            ret = true;
+            break;
+         }
+      }
+#endif
+   }
+   else
+   {
+      const char *str = (const char*)glGetString(GL_EXTENSIONS);
+      ret = str && strstr(str, ext);
+   }
+
+   return ret;
+}
+
+bool gl_check_error(char **error_string)
+{
+   int error = glGetError();
+   switch (error)
+   {
+      case GL_INVALID_ENUM:
+         *error_string = strdup("GL: Invalid enum.");
+         break;
+      case GL_INVALID_VALUE:
+         *error_string = strdup("GL: Invalid value.");
+         break;
+      case GL_INVALID_OPERATION:
+         *error_string = strdup("GL: Invalid operation.");
+         break;
+      case GL_OUT_OF_MEMORY:
+         *error_string = strdup("GL: Out of memory.");
+         break;
+      case GL_NO_ERROR:
+         return true;
+      default:
+         *error_string = strdup("Non specified GL error.");
+         break;
+   }
+
+   return false;
+}
+
+bool gl_check_capability(enum gl_capability_enum enum_idx)
+{
+   unsigned major       = 0;
+   unsigned minor       = 0;
+   const char *vendor   = (const char*)glGetString(GL_VENDOR);
+   const char *renderer = (const char*)glGetString(GL_RENDERER);
+   const char *version  = (const char*)glGetString(GL_VERSION);
+#ifdef HAVE_OPENGLES
+   if (version && sscanf(version, "OpenGL ES %u.%u", &major, &minor) != 2)
+#else
+   if (version && sscanf(version, "%u.%u", &major, &minor) != 2)
+#endif
+      major = minor = 0;
+
+   (void)vendor;
+   (void)renderer;
+
+   switch (enum_idx)
+   {
+      case GL_CAPS_GLES3_SUPPORTED:
+#if defined(HAVE_OPENGLES)
+         if (major >= 3)
+            return true;
+#endif
+         break;
+      case GL_CAPS_EGLIMAGE:
+#if defined(HAVE_EGL) && defined(HAVE_OPENGLES)
+         if (glEGLImageTargetTexture2DOES != NULL)
+            return true;
+#endif
+         break;
+      case GL_CAPS_SYNC:
+#ifdef HAVE_OPENGLES
+         if (major >= 3)
+            return true;
+#else
+         if (gl_query_extension("ARB_sync") &&
+               glFenceSync && glDeleteSync && glClientWaitSync)
+            return true;
+#endif
+         break;
+      case GL_CAPS_MIPMAP:
+         {
+            static bool extension_queried = false;
+            static bool extension         = false;
+
+            if (!extension_queried)
+            {
+               extension         = gl_query_extension("ARB_framebuffer_object");
+               extension_queried = true;
+            }
+
+            if (extension)
+               return true;
+         }
+         break;
+      case GL_CAPS_VAO:
+#ifndef HAVE_OPENGLES
+         if (!gl_query_core_context_in_use() && !gl_query_extension("ARB_vertex_array_object"))
+            return false;
+
+         if (glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays)
+            return true;
+#endif
+         break;
+      case GL_CAPS_FBO:
+#if defined(HAVE_PSGL) || defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2)
+         return true;
+#else
+         if (     !gl_query_core_context_in_use()
+               && !gl_query_extension("ARB_framebuffer_object")
+               && !gl_query_extension("EXT_framebuffer_object"))
+            return false;
+
+         if (gl_query_extension("ARB_framebuffer_object"))
+            return true;
+
+         if (gl_query_extension("EXT_framebuffer_object"))
+            return true;
+
+         if (major >= 3)
+            return true;
+         break;
+#endif
+      case GL_CAPS_ARGB8:
+#ifdef HAVE_OPENGLES
+         if (gl_query_extension("OES_rgb8_rgba8")
+               || gl_query_extension("ARM_rgba8")
+                  || major >= 3)
+            return true;
+#else
+         /* TODO/FIXME - implement this for non-GLES? */
+#endif
+         break;
+      case GL_CAPS_DEBUG:
+         if (gl_query_extension("KHR_debug"))
+            return true;
+#ifndef HAVE_OPENGLES
+         if (gl_query_extension("ARB_debug_output"))
+            return true;
+#endif
+         break;
+      case GL_CAPS_PACKED_DEPTH_STENCIL:
+         if (major >= 3)
+            return true;
+         if (gl_query_extension("OES_packed_depth_stencil"))
+            return true;
+         if (gl_query_extension("EXT_packed_depth_stencil"))
+            return true;
+         break;
+      case GL_CAPS_ES2_COMPAT:
+#ifndef HAVE_OPENGLES
+         /* ATI card detected, skipping check for GL_RGB565 support... */
+         if (vendor && renderer && (strstr(vendor, "ATI") || strstr(renderer, "ATI")))
+            return false;
+
+         if (gl_query_extension("ARB_ES2_compatibility"))
+            return true;
+#endif
+         break;
+      case GL_CAPS_UNPACK_ROW_LENGTH:
+#ifdef HAVE_OPENGLES
+         if (major >= 3)
+            return true;
+
+         /* Extension GL_EXT_unpack_subimage, can copy textures faster
+          * than using UNPACK_ROW_LENGTH */
+         if (gl_query_extension("GL_EXT_unpack_subimage"))
+            return true;
+#endif
+         break;
+      case GL_CAPS_FULL_NPOT_SUPPORT:
+         if (major >= 3)
+            return true;
+#ifdef HAVE_OPENGLES
+         if (gl_query_extension("ARB_texture_non_power_of_two") ||
+               gl_query_extension("OES_texture_npot"))
+            return true;
+#else
+         {
+            GLint max_texture_size = 0;
+            GLint max_native_instr = 0;
+            /* try to detect actual npot support. might fail for older cards. */
+            bool  arb_npot         = gl_query_extension("ARB_texture_non_power_of_two");
+            bool  arb_frag_program = gl_query_extension("ARB_fragment_program");
+
+            glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
+
+#ifdef GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB
+            if (arb_frag_program && glGetProgramivARB)
+               glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,
+                     GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &max_native_instr);
+#endif
+
+            if (arb_npot && arb_frag_program &&
+                  (max_texture_size >= 8192) && (max_native_instr >= 4096))
+               return true;
+         }
+#endif
+         break;
+      case GL_CAPS_SRGB_FBO_ES3:
+#ifdef HAVE_OPENGLES
+         if (major >= 3)
+            return true;
+#else
+         break;
+#endif
+      case GL_CAPS_SRGB_FBO:
+#if defined(HAVE_OPENGLES)
+         if (major >= 3 || gl_query_extension("EXT_sRGB"))
+            return true;
+#endif
+         if (gl_check_capability(GL_CAPS_FBO))
+         {
+            if (   gl_query_core_context_in_use() ||
+                  (gl_query_extension("EXT_texture_sRGB")
+                   && gl_query_extension("ARB_framebuffer_sRGB"))
+               )
+               return true;
+         }
+         break;
+      case GL_CAPS_FP_FBO:
+         /* GLES - No extensions for float FBO currently. */
+#ifndef HAVE_OPENGLES
+         if (gl_check_capability(GL_CAPS_FBO))
+         {
+            /* Float FBO is core in 3.2. */
+            if (gl_query_core_context_in_use() || gl_query_extension("ARB_texture_float"))
+               return true;
+         }
+#endif
+         break;
+      case GL_CAPS_BGRA8888:
+#ifdef HAVE_OPENGLES
+         /* There are both APPLE and EXT variants. */
+         if (gl_query_extension("BGRA8888"))
+            return true;
+#else
+         return true;
+#endif
+         break;
+      case GL_CAPS_TEX_STORAGE:
+#ifdef HAVE_OPENGLES
+         if (major >= 3)
+            return true;
+#else
+         if (vendor && strstr(vendor, "ATI Technologies"))
+            return false;
+         if (gl_query_extension("ARB_texture_storage"))
+            return true;
+#endif
+         break;
+      case GL_CAPS_TEX_STORAGE_EXT:
+#ifdef TARGET_OS_IPHONE
+           /* Not working on iOS */
+           return false;
+#else
+         if (gl_query_extension("EXT_texture_storage"))
+            return true;
+#endif
+         break;
+      case GL_CAPS_NONE:
+      default:
+         break;
+   }
+
+   return false;
+}
diff --git a/deps/libretro-common/gfx/scaler/pixconv.c b/deps/libretro-common/gfx/scaler/pixconv.c
new file mode 100644 (file)
index 0000000..276ab34
--- /dev/null
@@ -0,0 +1,1083 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (pixconv.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_inline.h>
+
+#include <gfx/scaler/pixconv.h>
+
+#if _MSC_VER && _MSC_VER <= 1800
+#define SCALER_NO_SIMD
+#endif
+
+#ifdef SCALER_NO_SIMD
+#undef __SSE2__
+#endif
+
+#if defined(__SSE2__)
+#include <emmintrin.h>
+#elif defined(__MMX__)
+#include <mmintrin.h>
+#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
+#include <arm_neon.h>
+#endif
+
+void conv_rgb565_0rgb1555(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input = (const uint16_t*)input_;
+   uint16_t *output = (uint16_t*)output_;
+
+#if defined(__SSE2__)
+   int max_width           = width - 7;
+   const __m128i hi_mask   = _mm_set1_epi16(0x7fe0);
+   const __m128i lo_mask   = _mm_set1_epi16(0x1f);
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 1, input += in_stride >> 1)
+   {
+      int w = 0;
+#if defined(__SSE2__)
+      for (; w < max_width; w += 8)
+      {
+         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
+         __m128i hi = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);
+         __m128i lo = _mm_and_si128(in, lo_mask);
+         _mm_storeu_si128((__m128i*)(output + w), _mm_or_si128(hi, lo));
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint16_t col = input[w];
+         uint16_t hi  = (col >> 1) & 0x7fe0;
+         uint16_t lo  = col & 0x1f;
+         output[w]    = hi | lo;
+      }
+   }
+}
+
+void conv_0rgb1555_rgb565(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input   = (const uint16_t*)input_;
+   uint16_t *output        = (uint16_t*)output_;
+
+#if defined(__SSE2__)
+   int max_width           = width - 7;
+
+   const __m128i hi_mask   = _mm_set1_epi16(
+         (int16_t)((0x1f << 11) | (0x1f << 6)));
+   const __m128i lo_mask   = _mm_set1_epi16(0x1f);
+   const __m128i glow_mask = _mm_set1_epi16(1 << 5);
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 1, input += in_stride >> 1)
+   {
+      int w = 0;
+#if defined(__SSE2__)
+      for (; w < max_width; w += 8)
+      {
+         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
+         __m128i rg   = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);
+         __m128i b    = _mm_and_si128(in, lo_mask);
+         __m128i glow = _mm_and_si128(_mm_srli_epi16(in, 4), glow_mask);
+         _mm_storeu_si128((__m128i*)(output + w),
+               _mm_or_si128(rg, _mm_or_si128(b, glow)));
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint16_t col  = input[w];
+         uint16_t rg   = (col << 1) & ((0x1f << 11) | (0x1f << 6));
+         uint16_t b    = col & 0x1f;
+         uint16_t glow = (col >> 4) & (1 << 5);
+         output[w]     = rg | b | glow;
+      }
+   }
+}
+
+void conv_0rgb1555_argb8888(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input = (const uint16_t*)input_;
+   uint32_t *output      = (uint32_t*)output_;
+
+#ifdef __SSE2__
+   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f << 10);
+   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f <<  5);
+   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);
+   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);
+   const __m128i a           = _mm_set1_epi16(0x00ff);
+
+   int max_width = width - 7;
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 2, input += in_stride >> 1)
+   {
+      int w = 0;
+#ifdef __SSE2__
+      for (; w < max_width; w += 8)
+      {
+         __m128i res_lo_bg, res_hi_bg;
+         __m128i res_lo_ra, res_hi_ra;
+         __m128i res_lo, res_hi;
+         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
+         __m128i r = _mm_and_si128(in, pix_mask_r);
+         __m128i g = _mm_and_si128(in, pix_mask_gb);
+         __m128i b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_gb);
+
+         r = _mm_mulhi_epi16(r, mul15_hi);
+         g = _mm_mulhi_epi16(g, mul15_mid);
+         b = _mm_mulhi_epi16(b, mul15_mid);
+
+         res_lo_bg = _mm_unpacklo_epi8(b, g);
+         res_hi_bg = _mm_unpackhi_epi8(b, g);
+         res_lo_ra = _mm_unpacklo_epi8(r, a);
+         res_hi_ra = _mm_unpackhi_epi8(r, a);
+
+         res_lo = _mm_or_si128(res_lo_bg,
+               _mm_slli_si128(res_lo_ra, 2));
+         res_hi = _mm_or_si128(res_hi_bg,
+               _mm_slli_si128(res_hi_ra, 2));
+
+         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
+         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t r   = (col >> 10) & 0x1f;
+         uint32_t g   = (col >>  5) & 0x1f;
+         uint32_t b   = (col >>  0) & 0x1f;
+         r            = (r << 3) | (r >> 2);
+         g            = (g << 3) | (g >> 2);
+         b            = (b << 3) | (b >> 2);
+
+         output[w]    = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
+      }
+   }
+}
+
+void conv_rgb565_argb8888(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input    = (const uint16_t*)input_;
+   uint32_t *output         = (uint32_t*)output_;
+
+#if defined(__SSE2__)
+   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);
+   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);
+   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);
+   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
+   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
+   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
+   const __m128i a          = _mm_set1_epi16(0x00ff);
+
+   int max_width            = width - 7;
+#elif defined(__MMX__)
+   const __m64 pix_mask_r = _mm_set1_pi16(0x1f << 10);
+   const __m64 pix_mask_g = _mm_set1_pi16(0x3f << 5);
+   const __m64 pix_mask_b = _mm_set1_pi16(0x1f << 5);
+   const __m64 mul16_r    = _mm_set1_pi16(0x0210);
+   const __m64 mul16_g    = _mm_set1_pi16(0x2080);
+   const __m64 mul16_b    = _mm_set1_pi16(0x4200);
+   const __m64 a          = _mm_set1_pi16(0x00ff);
+
+   int max_width            = width - 3;
+#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
+   int max_width            = width - 7;
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 2, input += in_stride >> 1)
+   {
+      int w = 0;
+#if defined(__SSE2__)
+      for (; w < max_width; w += 8)
+      {
+         __m128i res_lo, res_hi;
+         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
+         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
+         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);
+         __m128i        g = _mm_and_si128(in, pix_mask_g);
+         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);
+
+         r                = _mm_mulhi_epi16(r, mul16_r);
+         g                = _mm_mulhi_epi16(g, mul16_g);
+         b                = _mm_mulhi_epi16(b, mul16_b);
+
+         res_lo_bg        = _mm_unpacklo_epi8(b, g);
+         res_hi_bg        = _mm_unpackhi_epi8(b, g);
+         res_lo_ra        = _mm_unpacklo_epi8(r, a);
+         res_hi_ra        = _mm_unpackhi_epi8(r, a);
+
+         res_lo           = _mm_or_si128(res_lo_bg,
+               _mm_slli_si128(res_lo_ra, 2));
+         res_hi           = _mm_or_si128(res_hi_bg,
+               _mm_slli_si128(res_hi_ra, 2));
+
+         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
+         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
+      }
+#elif defined(__MMX__)
+      for (; w < max_width; w += 4)
+      {
+         __m64 res_lo, res_hi;
+         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
+         const __m64 in = *((__m64*)(input + w));
+         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 1), pix_mask_r);
+         __m64          g = _mm_and_si64(in, pix_mask_g);
+         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 5), pix_mask_b);
+
+         r                = _mm_mulhi_pi16(r, mul16_r);
+         g                = _mm_mulhi_pi16(g, mul16_g);
+         b                = _mm_mulhi_pi16(b, mul16_b);
+
+         res_lo_bg        = _mm_unpacklo_pi8(b, g);
+         res_hi_bg        = _mm_unpackhi_pi8(b, g);
+         res_lo_ra        = _mm_unpacklo_pi8(r, a);
+         res_hi_ra        = _mm_unpackhi_pi8(r, a);
+
+         res_lo           = _mm_or_si64(res_lo_bg,
+               _mm_slli_si64(res_lo_ra, 16));
+         res_hi           = _mm_or_si64(res_hi_bg,
+               _mm_slli_si64(res_hi_ra, 16));
+
+         *((__m64*)(output + w + 0)) = res_lo;
+         *((__m64*)(output + w + 2)) = res_hi;
+      }
+
+      _mm_empty();
+#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
+      for (; w < max_width; w += 8)
+      {
+         uint16x8_t in = vld1q_u16(input + w);
+
+         uint16x8_t r = vsriq_n_u16(in, in, 5);
+         uint16x8_t b = vsliq_n_u16(in, in, 5);
+         uint16x8_t g = vsriq_n_u16(b,  b,  6);
+
+         uint8x8x4_t res;
+         res.val[3] = vdup_n_u8(0xffu);
+         res.val[2] = vshrn_n_u16(r, 8);
+         res.val[1] = vshrn_n_u16(g, 8);
+         res.val[0] = vshrn_n_u16(b, 2);
+
+         vst4_u8((uint8_t*)(output + w), res);
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t r   = (col >> 11) & 0x1f;
+         uint32_t g   = (col >>  5) & 0x3f;
+         uint32_t b   = (col >>  0) & 0x1f;
+         r            = (r << 3) | (r >> 2);
+         g            = (g << 2) | (g >> 4);
+         b            = (b << 3) | (b >> 2);
+
+         output[w]    = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
+      }
+   }
+}
+
+void conv_rgb565_abgr8888(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input    = (const uint16_t*)input_;
+   uint32_t *output         = (uint32_t*)output_;
+ #if defined(__SSE2__)
+   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);
+   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);
+   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);
+   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
+   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
+   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
+   const __m128i a          = _mm_set1_epi16(0x00ff);
+    int max_width            = width - 7;
+#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
+   int max_width            = width - 7;
+#endif
+    for (h = 0; h < height;
+         h++, output += out_stride >> 2, input += in_stride >> 1)
+   {
+      int w = 0;
+#if defined(__SSE2__)
+      for (; w < max_width; w += 8)
+      {
+         __m128i res_lo, res_hi;
+         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
+         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));
+         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);
+         __m128i        g = _mm_and_si128(in, pix_mask_g);
+         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);
+         r                = _mm_mulhi_epi16(r, mul16_r);
+         g                = _mm_mulhi_epi16(g, mul16_g);
+         b                = _mm_mulhi_epi16(b, mul16_b);
+         res_lo_bg        = _mm_unpacklo_epi8(b, g);
+         res_hi_bg        = _mm_unpackhi_epi8(b, g);
+         res_lo_ra        = _mm_unpacklo_epi8(r, a);
+         res_hi_ra        = _mm_unpackhi_epi8(r, a);
+         res_lo           = _mm_or_si128(res_lo_bg,
+               _mm_slli_si128(res_lo_ra, 2));
+         res_hi           = _mm_or_si128(res_hi_bg,
+               _mm_slli_si128(res_hi_ra, 2));
+         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);
+         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);
+      }
+#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))
+      for (; w < max_width; w += 8)
+      {
+         uint16x8_t in = vld1q_u16(input + w);
+
+         uint16x8_t r = vsriq_n_u16(in, in, 5);
+         uint16x8_t b = vsliq_n_u16(in, in, 5);
+         uint16x8_t g = vsriq_n_u16(b,  b,  6);
+
+         uint8x8x4_t res;
+         res.val[3] = vdup_n_u8(0xffu);
+         res.val[2] = vshrn_n_u16(b, 2);
+         res.val[1] = vshrn_n_u16(g, 8);
+         res.val[0] = vshrn_n_u16(r, 8);
+
+         vst4_u8((uint8_t*)(output + w), res);
+      }
+#endif
+       for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t r   = (col >> 11) & 0x1f;
+         uint32_t g   = (col >>  5) & 0x3f;
+         uint32_t b   = (col >>  0) & 0x1f;
+         r            = (r << 3) | (r >> 2);
+         g            = (g << 2) | (g >> 4);
+         b            = (b << 3) | (b >> 2);
+         output[w]    = (0xffu << 24) | (b << 16) | (g << 8) | (r << 0);
+      }
+   }
+}
+
+void conv_argb8888_rgba4444(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h, w;
+   const uint32_t *input = (const uint32_t*)input_;
+   uint16_t *output      = (uint16_t*)output_;
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 2, input += in_stride >> 1)
+   {
+      for (w = 0; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t r   = (col >> 16) & 0xf;
+         uint32_t g   = (col >>  8) & 0xf;
+         uint32_t b   = (col) & 0xf;
+         uint32_t a   = (col >>  24) & 0xf;
+         r            = (r >> 4) | r;
+         g            = (g >> 4) | g;
+         b            = (b >> 4) | b;
+         a            = (a >> 4) | a;
+
+         output[w]    = (r << 12) | (g << 8) | (b << 4) | a;
+      }
+   }
+}
+
+void conv_rgba4444_argb8888(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input = (const uint16_t*)input_;
+   uint32_t *output      = (uint32_t*)output_;
+
+#if defined(__MMX__)
+   const __m64 pix_mask_r = _mm_set1_pi16(0xf << 10);
+   const __m64 pix_mask_g = _mm_set1_pi16(0xf << 8);
+   const __m64 pix_mask_b = _mm_set1_pi16(0xf << 8);
+   const __m64 mul16_r    = _mm_set1_pi16(0x0440);
+   const __m64 mul16_g    = _mm_set1_pi16(0x1100);
+   const __m64 mul16_b    = _mm_set1_pi16(0x1100);
+   const __m64 a          = _mm_set1_pi16(0x00ff);
+
+   int max_width            = width - 3;
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 2, input += in_stride >> 1)
+   {
+      int w = 0;
+#if defined(__MMX__)
+      for (; w < max_width; w += 4)
+      {
+         __m64 res_lo, res_hi;
+         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
+         const __m64 in = *((__m64*)(input + w));
+         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 2), pix_mask_r);
+         __m64          g = _mm_and_si64(in, pix_mask_g);
+         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 4), pix_mask_b);
+
+         r                = _mm_mulhi_pi16(r, mul16_r);
+         g                = _mm_mulhi_pi16(g, mul16_g);
+         b                = _mm_mulhi_pi16(b, mul16_b);
+
+         res_lo_bg        = _mm_unpacklo_pi8(b, g);
+         res_hi_bg        = _mm_unpackhi_pi8(b, g);
+         res_lo_ra        = _mm_unpacklo_pi8(r, a);
+         res_hi_ra        = _mm_unpackhi_pi8(r, a);
+
+         res_lo           = _mm_or_si64(res_lo_bg,
+               _mm_slli_si64(res_lo_ra, 16));
+         res_hi           = _mm_or_si64(res_hi_bg,
+               _mm_slli_si64(res_hi_ra, 16));
+
+         *((__m64*)(output + w + 0)) = res_lo;
+         *((__m64*)(output + w + 2)) = res_hi;
+      }
+
+      _mm_empty();
+#endif
+
+      for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t r   = (col >> 12) & 0xf;
+         uint32_t g   = (col >>  8) & 0xf;
+         uint32_t b   = (col >>  4) & 0xf;
+         uint32_t a   = (col >>  0) & 0xf;
+         r            = (r << 4) | r;
+         g            = (g << 4) | g;
+         b            = (b << 4) | b;
+         a            = (a << 4) | a;
+
+         output[w]    = (a << 24) | (r << 16) | (g << 8) | (b << 0);
+      }
+   }
+}
+
+void conv_rgba4444_rgb565(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h, w;
+   const uint16_t *input = (const uint16_t*)input_;
+   uint16_t *output      = (uint16_t*)output_;
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 1, input += in_stride >> 1)
+   {
+      for (w = 0; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t r   = (col >> 12) & 0xf;
+         uint32_t g   = (col >>  8) & 0xf;
+         uint32_t b   = (col >>  4) & 0xf;
+
+         output[w]    = (r << 12) | (g << 7) | (b << 1);
+      }
+   }
+}
+
+#if defined(__SSE2__)
+/* :( TODO: Make this saner. */
+static INLINE void store_bgr24_sse2(void *output, __m128i a,
+      __m128i b, __m128i c, __m128i d)
+{
+   const __m128i mask_0 = _mm_set_epi32(0, 0, 0, 0x00ffffff);
+   const __m128i mask_1 = _mm_set_epi32(0, 0, 0x00ffffff, 0);
+   const __m128i mask_2 = _mm_set_epi32(0, 0x00ffffff, 0, 0);
+   const __m128i mask_3 = _mm_set_epi32(0x00ffffff, 0, 0, 0);
+
+   __m128i a0 = _mm_and_si128(a, mask_0);
+   __m128i a1 = _mm_srli_si128(_mm_and_si128(a, mask_1),  1);
+   __m128i a2 = _mm_srli_si128(_mm_and_si128(a, mask_2),  2);
+   __m128i a3 = _mm_srli_si128(_mm_and_si128(a, mask_3),  3);
+   __m128i a4 = _mm_slli_si128(_mm_and_si128(b, mask_0), 12);
+   __m128i a5 = _mm_slli_si128(_mm_and_si128(b, mask_1), 11);
+
+   __m128i b0 = _mm_srli_si128(_mm_and_si128(b, mask_1), 5);
+   __m128i b1 = _mm_srli_si128(_mm_and_si128(b, mask_2), 6);
+   __m128i b2 = _mm_srli_si128(_mm_and_si128(b, mask_3), 7);
+   __m128i b3 = _mm_slli_si128(_mm_and_si128(c, mask_0), 8);
+   __m128i b4 = _mm_slli_si128(_mm_and_si128(c, mask_1), 7);
+   __m128i b5 = _mm_slli_si128(_mm_and_si128(c, mask_2), 6);
+
+   __m128i c0 = _mm_srli_si128(_mm_and_si128(c, mask_2), 10);
+   __m128i c1 = _mm_srli_si128(_mm_and_si128(c, mask_3), 11);
+   __m128i c2 = _mm_slli_si128(_mm_and_si128(d, mask_0),  4);
+   __m128i c3 = _mm_slli_si128(_mm_and_si128(d, mask_1),  3);
+   __m128i c4 = _mm_slli_si128(_mm_and_si128(d, mask_2),  2);
+   __m128i c5 = _mm_slli_si128(_mm_and_si128(d, mask_3),  1);
+
+   __m128i *out = (__m128i*)output;
+
+   _mm_storeu_si128(out + 0,
+         _mm_or_si128(a0, _mm_or_si128(a1, _mm_or_si128(a2,
+                  _mm_or_si128(a3, _mm_or_si128(a4, a5))))));
+
+   _mm_storeu_si128(out + 1,
+         _mm_or_si128(b0, _mm_or_si128(b1, _mm_or_si128(b2,
+                  _mm_or_si128(b3, _mm_or_si128(b4, b5))))));
+
+   _mm_storeu_si128(out + 2,
+         _mm_or_si128(c0, _mm_or_si128(c1, _mm_or_si128(c2,
+                  _mm_or_si128(c3, _mm_or_si128(c4, c5))))));
+}
+#endif
+
+void conv_0rgb1555_bgr24(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input     = (const uint16_t*)input_;
+   uint8_t *output           = (uint8_t*)output_;
+
+#if defined(__SSE2__)
+   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f << 10);
+   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f <<  5);
+   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);
+   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);
+   const __m128i a           = _mm_set1_epi16(0x00ff);
+
+   int max_width             = width - 15;
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride, input += in_stride >> 1)
+   {
+      uint8_t *out = output;
+      int   w = 0;
+
+#if defined(__SSE2__)
+      for (; w < max_width; w += 16, out += 48)
+      {
+         __m128i res_lo_bg0, res_lo_bg1, res_hi_bg0, res_hi_bg1,
+                 res_lo_ra0, res_lo_ra1, res_hi_ra0, res_hi_ra1,
+                 res_lo0, res_lo1, res_hi0, res_hi1;
+         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w + 0));
+         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));
+         __m128i r0        = _mm_and_si128(in0, pix_mask_r);
+         __m128i r1        = _mm_and_si128(in1, pix_mask_r);
+         __m128i g0        = _mm_and_si128(in0, pix_mask_gb);
+         __m128i g1        = _mm_and_si128(in1, pix_mask_gb);
+         __m128i b0        = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_gb);
+         __m128i b1        = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_gb);
+
+         r0                = _mm_mulhi_epi16(r0, mul15_hi);
+         r1                = _mm_mulhi_epi16(r1, mul15_hi);
+         g0                = _mm_mulhi_epi16(g0, mul15_mid);
+         g1                = _mm_mulhi_epi16(g1, mul15_mid);
+         b0                = _mm_mulhi_epi16(b0, mul15_mid);
+         b1                = _mm_mulhi_epi16(b1, mul15_mid);
+
+         res_lo_bg0        = _mm_unpacklo_epi8(b0, g0);
+         res_lo_bg1        = _mm_unpacklo_epi8(b1, g1);
+         res_hi_bg0        = _mm_unpackhi_epi8(b0, g0);
+         res_hi_bg1        = _mm_unpackhi_epi8(b1, g1);
+         res_lo_ra0        = _mm_unpacklo_epi8(r0, a);
+         res_lo_ra1        = _mm_unpacklo_epi8(r1, a);
+         res_hi_ra0        = _mm_unpackhi_epi8(r0, a);
+         res_hi_ra1        = _mm_unpackhi_epi8(r1, a);
+
+         res_lo0           = _mm_or_si128(res_lo_bg0,
+               _mm_slli_si128(res_lo_ra0, 2));
+         res_lo1           = _mm_or_si128(res_lo_bg1,
+               _mm_slli_si128(res_lo_ra1, 2));
+         res_hi0           = _mm_or_si128(res_hi_bg0,
+               _mm_slli_si128(res_hi_ra0, 2));
+         res_hi1           = _mm_or_si128(res_hi_bg1,
+               _mm_slli_si128(res_hi_ra1, 2));
+
+         /* Non-POT pixel sizes for the loss */
+         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t b   = (col >>  0) & 0x1f;
+         uint32_t g   = (col >>  5) & 0x1f;
+         uint32_t r   = (col >> 10) & 0x1f;
+         b            = (b << 3) | (b >> 2);
+         g            = (g << 3) | (g >> 2);
+         r            = (r << 3) | (r >> 2);
+
+         *out++       = b;
+         *out++       = g;
+         *out++       = r;
+      }
+   }
+}
+
+void conv_rgb565_bgr24(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint16_t *input    = (const uint16_t*)input_;
+   uint8_t *output          = (uint8_t*)output_;
+
+#if defined(__SSE2__)
+   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);
+   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);
+   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);
+   const __m128i mul16_r    = _mm_set1_epi16(0x0210);
+   const __m128i mul16_g    = _mm_set1_epi16(0x2080);
+   const __m128i mul16_b    = _mm_set1_epi16(0x4200);
+   const __m128i a          = _mm_set1_epi16(0x00ff);
+
+   int max_width            = width - 15;
+#endif
+
+   for (h = 0; h < height; h++, output += out_stride, input += in_stride >> 1)
+   {
+      uint8_t *out = output;
+      int        w = 0;
+#if defined(__SSE2__)
+      for (; w < max_width; w += 16, out += 48)
+      {
+         __m128i res_lo_bg0, res_hi_bg0, res_lo_ra0, res_hi_ra0;
+         __m128i res_lo_bg1, res_hi_bg1, res_lo_ra1, res_hi_ra1;
+         __m128i res_lo0, res_hi0, res_lo1, res_hi1;
+         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w));
+         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));
+         __m128i r0 = _mm_and_si128(_mm_srli_epi16(in0, 1), pix_mask_r);
+         __m128i g0 = _mm_and_si128(in0, pix_mask_g);
+         __m128i b0 = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_b);
+         __m128i r1 = _mm_and_si128(_mm_srli_epi16(in1, 1), pix_mask_r);
+         __m128i g1 = _mm_and_si128(in1, pix_mask_g);
+         __m128i b1 = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_b);
+
+         r0         = _mm_mulhi_epi16(r0, mul16_r);
+         g0         = _mm_mulhi_epi16(g0, mul16_g);
+         b0         = _mm_mulhi_epi16(b0, mul16_b);
+         r1         = _mm_mulhi_epi16(r1, mul16_r);
+         g1         = _mm_mulhi_epi16(g1, mul16_g);
+         b1         = _mm_mulhi_epi16(b1, mul16_b);
+
+         res_lo_bg0 = _mm_unpacklo_epi8(b0, g0);
+         res_hi_bg0 = _mm_unpackhi_epi8(b0, g0);
+         res_lo_ra0 = _mm_unpacklo_epi8(r0, a);
+         res_hi_ra0 = _mm_unpackhi_epi8(r0, a);
+         res_lo_bg1 = _mm_unpacklo_epi8(b1, g1);
+         res_hi_bg1 = _mm_unpackhi_epi8(b1, g1);
+         res_lo_ra1 = _mm_unpacklo_epi8(r1, a);
+         res_hi_ra1 = _mm_unpackhi_epi8(r1, a);
+
+         res_lo0    = _mm_or_si128(res_lo_bg0,
+               _mm_slli_si128(res_lo_ra0, 2));
+         res_hi0    = _mm_or_si128(res_hi_bg0,
+               _mm_slli_si128(res_hi_ra0, 2));
+         res_lo1    = _mm_or_si128(res_lo_bg1,
+               _mm_slli_si128(res_lo_ra1, 2));
+         res_hi1    = _mm_or_si128(res_hi_bg1,
+               _mm_slli_si128(res_hi_ra1, 2));
+
+         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint32_t r   = (col >> 11) & 0x1f;
+         uint32_t g   = (col >>  5) & 0x3f;
+         uint32_t b   = (col >>  0) & 0x1f;
+         r = (r << 3) | (r >> 2);
+         g = (g << 2) | (g >> 4);
+         b = (b << 3) | (b >> 2);
+
+         *out++ = b;
+         *out++ = g;
+         *out++ = r;
+      }
+   }
+}
+
+void conv_bgr24_argb8888(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h, w;
+   const uint8_t *input = (const uint8_t*)input_;
+   uint32_t *output     = (uint32_t*)output_;
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 2, input += in_stride)
+   {
+      const uint8_t *inp = input;
+      for (w = 0; w < width; w++)
+      {
+         uint32_t b = *inp++;
+         uint32_t g = *inp++;
+         uint32_t r = *inp++;
+         output[w]  = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
+      }
+   }
+}
+
+void conv_bgr24_rgb565(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h, w;
+   const uint8_t *input = (const uint8_t*)input_;
+   uint16_t *output     = (uint16_t*)output_;
+   for (h = 0; h < height;
+         h++, output += out_stride, input += in_stride)
+   {
+      const uint8_t *inp = input;
+      for (w = 0; w < width; w++)
+      {
+         uint16_t b = *inp++;
+         uint16_t g = *inp++;
+         uint16_t r = *inp++;
+    
+         output[w] = ((r & 0x00F8) << 8) | ((g&0x00FC) << 3) | ((b&0x00F8) >> 3);
+      }  
+   }
+}
+
+void conv_argb8888_0rgb1555(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h, w;
+   const uint32_t *input = (const uint32_t*)input_;
+   uint16_t *output      = (uint16_t*)output_;
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 1, input += in_stride >> 2)
+   {
+      for (w = 0; w < width; w++)
+      {
+         uint32_t col = input[w];
+         uint16_t r   = (col >> 19) & 0x1f;
+         uint16_t g   = (col >> 11) & 0x1f;
+         uint16_t b   = (col >>  3) & 0x1f;
+         output[w]    = (r << 10) | (g << 5) | (b << 0);
+      }
+   }
+}
+
+void conv_argb8888_bgr24(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint32_t *input = (const uint32_t*)input_;
+   uint8_t *output       = (uint8_t*)output_;
+
+#if defined(__SSE2__)
+   int max_width = width - 15;
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride, input += in_stride >> 2)
+   {
+      uint8_t *out = output;
+      int        w = 0;
+#if defined(__SSE2__)
+      for (; w < max_width; w += 16, out += 48)
+      {
+         __m128i l0 = _mm_loadu_si128((const __m128i*)(input + w +  0));
+         __m128i l1 = _mm_loadu_si128((const __m128i*)(input + w +  4));
+         __m128i l2 = _mm_loadu_si128((const __m128i*)(input + w +  8));
+         __m128i l3 = _mm_loadu_si128((const __m128i*)(input + w + 12));
+         store_bgr24_sse2(out, l0, l1, l2, l3);
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         *out++       = (uint8_t)(col >>  0);
+         *out++       = (uint8_t)(col >>  8);
+         *out++       = (uint8_t)(col >> 16);
+      }
+   }
+}
+
+#if defined(__SSE2__)
+static INLINE __m128i conv_shuffle_rb_epi32(__m128i c)
+{
+   /* SSSE3 plz */
+   const __m128i b_mask = _mm_set1_epi32(0x000000ff);
+   const __m128i g_mask = _mm_set1_epi32(0x0000ff00);
+   const __m128i r_mask = _mm_set1_epi32(0x00ff0000);
+   __m128i sl = _mm_and_si128(_mm_slli_epi32(c, 16), r_mask);
+   __m128i sr = _mm_and_si128(_mm_srli_epi32(c, 16), b_mask);
+   __m128i g  = _mm_and_si128(c, g_mask);
+   __m128i rb = _mm_or_si128(sl, sr);
+   return _mm_or_si128(g, rb);
+}
+#endif
+
+void conv_abgr8888_bgr24(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint32_t *input = (const uint32_t*)input_;
+   uint8_t *output       = (uint8_t*)output_;
+
+#if defined(__SSE2__)
+   int max_width = width - 15;
+#endif
+
+   for (h = 0; h < height;
+         h++, output += out_stride, input += in_stride >> 2)
+   {
+      uint8_t *out = output;
+      int        w = 0;
+#if defined(__SSE2__)
+      for (; w < max_width; w += 16, out += 48)
+      {
+                __m128i a = _mm_loadu_si128((const __m128i*)(input + w +  0));
+                __m128i b = _mm_loadu_si128((const __m128i*)(input + w +  4));
+                __m128i c = _mm_loadu_si128((const __m128i*)(input + w +  8));
+                __m128i d = _mm_loadu_si128((const __m128i*)(input + w + 12));
+         a = conv_shuffle_rb_epi32(a);
+         b = conv_shuffle_rb_epi32(b);
+         c = conv_shuffle_rb_epi32(c);
+         d = conv_shuffle_rb_epi32(d);
+         store_bgr24_sse2(out, a, b, c, d);
+      }
+#endif
+
+      for (; w < width; w++)
+      {
+         uint32_t col = input[w];
+         *out++       = (uint8_t)(col >> 16);
+         *out++       = (uint8_t)(col >>  8);
+         *out++       = (uint8_t)(col >>  0);
+      }
+   }
+}
+
+void conv_argb8888_abgr8888(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h, w;
+   const uint32_t *input = (const uint32_t*)input_;
+   uint32_t *output      = (uint32_t*)output_;
+
+   for (h = 0; h < height;
+         h++, output += out_stride >> 2, input += in_stride >> 2)
+   {
+      for (w = 0; w < width; w++)
+      {
+         uint32_t col = input[w];
+         output[w]    = ((col << 16) & 0xff0000) |
+            ((col >> 16) & 0xff) | (col & 0xff00ff00);
+      }
+   }
+}
+
+#define YUV_SHIFT 6
+#define YUV_OFFSET (1 << (YUV_SHIFT - 1))
+#define YUV_MAT_Y (1 << 6)
+#define YUV_MAT_U_G (-22)
+#define YUV_MAT_U_B (113)
+#define YUV_MAT_V_R (90)
+#define YUV_MAT_V_G (-46)
+
+void conv_yuyv_argb8888(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   const uint8_t *input        = (const uint8_t*)input_;
+   uint32_t *output            = (uint32_t*)output_;
+
+#if defined(__SSE2__)
+   const __m128i mask_y        = _mm_set1_epi16(0xffu);
+   const __m128i mask_u        = _mm_set1_epi32(0xffu << 8);
+   const __m128i mask_v        = _mm_set1_epi32(0xffu << 24);
+   const __m128i chroma_offset = _mm_set1_epi16(128);
+   const __m128i round_offset  = _mm_set1_epi16(YUV_OFFSET);
+
+   const __m128i yuv_mul       = _mm_set1_epi16(YUV_MAT_Y);
+   const __m128i u_g_mul       = _mm_set1_epi16(YUV_MAT_U_G);
+   const __m128i u_b_mul       = _mm_set1_epi16(YUV_MAT_U_B);
+   const __m128i v_r_mul       = _mm_set1_epi16(YUV_MAT_V_R);
+   const __m128i v_g_mul       = _mm_set1_epi16(YUV_MAT_V_G);
+   const __m128i a             = _mm_cmpeq_epi16(
+         _mm_setzero_si128(), _mm_setzero_si128());
+#endif
+
+   for (h = 0; h < height; h++, output += out_stride >> 2, input += in_stride)
+   {
+      const uint8_t *src = input;
+      uint32_t      *dst = output;
+      int              w = 0;
+
+#if defined(__SSE2__)
+      /* Each loop processes 16 pixels. */
+      for (; w + 16 <= width; w += 16, src += 32, dst += 16)
+      {
+         __m128i u, v, u0_g, u1_g, u0_b, u1_b, v0_r, v1_r, v0_g, v1_g,
+                 r0, g0, b0, r1, g1, b1;
+         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;
+         __m128i res0, res1, res2, res3;
+         __m128i yuv0 = _mm_loadu_si128((const __m128i*)(src +  0)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */
+         __m128i yuv1 = _mm_loadu_si128((const __m128i*)(src + 16)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */
+
+         __m128i _y0 = _mm_and_si128(yuv0, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */
+         __m128i u0 = _mm_and_si128(yuv0, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */
+         __m128i v0 = _mm_and_si128(yuv0, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */
+         __m128i _y1 = _mm_and_si128(yuv1, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */
+         __m128i u1 = _mm_and_si128(yuv1, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */
+         __m128i v1 = _mm_and_si128(yuv1, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */
+
+         /* Juggle around to get U and V in the same 16-bit format as Y. */
+         u0 = _mm_srli_si128(u0, 1);
+         v0 = _mm_srli_si128(v0, 3);
+         u1 = _mm_srli_si128(u1, 1);
+         v1 = _mm_srli_si128(v1, 3);
+         u = _mm_packs_epi32(u0, u1);
+         v = _mm_packs_epi32(v0, v1);
+
+         /* Apply YUV offsets (U, V) -= (-128, -128). */
+         u = _mm_sub_epi16(u, chroma_offset);
+         v = _mm_sub_epi16(v, chroma_offset);
+
+         /* Upscale chroma horizontally (nearest). */
+         u0 = _mm_unpacklo_epi16(u, u);
+         u1 = _mm_unpackhi_epi16(u, u);
+         v0 = _mm_unpacklo_epi16(v, v);
+         v1 = _mm_unpackhi_epi16(v, v);
+
+         /* Apply transformations. */
+         _y0 = _mm_mullo_epi16(_y0, yuv_mul);
+         _y1 = _mm_mullo_epi16(_y1, yuv_mul);
+         u0_g   = _mm_mullo_epi16(u0, u_g_mul);
+         u1_g   = _mm_mullo_epi16(u1, u_g_mul);
+         u0_b   = _mm_mullo_epi16(u0, u_b_mul);
+         u1_b   = _mm_mullo_epi16(u1, u_b_mul);
+         v0_r   = _mm_mullo_epi16(v0, v_r_mul);
+         v1_r   = _mm_mullo_epi16(v1, v_r_mul);
+         v0_g   = _mm_mullo_epi16(v0, v_g_mul);
+         v1_g   = _mm_mullo_epi16(v1, v_g_mul);
+
+         /* Add contibutions from the transformed components. */
+         r0 = _mm_srai_epi16(_mm_adds_epi16(_mm_adds_epi16(_y0, v0_r),
+                  round_offset), YUV_SHIFT);
+         g0 = _mm_srai_epi16(_mm_adds_epi16(
+                  _mm_adds_epi16(_mm_adds_epi16(_y0, v0_g), u0_g), round_offset), YUV_SHIFT);
+         b0 = _mm_srai_epi16(_mm_adds_epi16(
+                  _mm_adds_epi16(_y0, u0_b), round_offset), YUV_SHIFT);
+
+         r1 = _mm_srai_epi16(_mm_adds_epi16(
+                  _mm_adds_epi16(_y1, v1_r), round_offset), YUV_SHIFT);
+         g1 = _mm_srai_epi16(_mm_adds_epi16(
+                  _mm_adds_epi16(_mm_adds_epi16(_y1, v1_g), u1_g), round_offset), YUV_SHIFT);
+         b1 = _mm_srai_epi16(_mm_adds_epi16(
+                  _mm_adds_epi16(_y1, u1_b), round_offset), YUV_SHIFT);
+
+         /* Saturate into 8-bit. */
+         r0 = _mm_packus_epi16(r0, r1);
+         g0 = _mm_packus_epi16(g0, g1);
+         b0 = _mm_packus_epi16(b0, b1);
+
+         /* Interleave into ARGB. */
+         res_lo_bg = _mm_unpacklo_epi8(b0, g0);
+         res_hi_bg = _mm_unpackhi_epi8(b0, g0);
+         res_lo_ra = _mm_unpacklo_epi8(r0, a);
+         res_hi_ra = _mm_unpackhi_epi8(r0, a);
+         res0 = _mm_unpacklo_epi16(res_lo_bg, res_lo_ra);
+         res1 = _mm_unpackhi_epi16(res_lo_bg, res_lo_ra);
+         res2 = _mm_unpacklo_epi16(res_hi_bg, res_hi_ra);
+         res3 = _mm_unpackhi_epi16(res_hi_bg, res_hi_ra);
+
+         _mm_storeu_si128((__m128i*)(dst +  0), res0);
+         _mm_storeu_si128((__m128i*)(dst +  4), res1);
+         _mm_storeu_si128((__m128i*)(dst +  8), res2);
+         _mm_storeu_si128((__m128i*)(dst + 12), res3);
+      }
+#endif
+
+      /* Finish off the rest (if any) in C. */
+      for (; w < width; w += 2, src += 4, dst += 2)
+      {
+         int _y0    = src[0];
+         int  u     = src[1] - 128;
+         int _y1    = src[2];
+         int  v     = src[3] - 128;
+
+         uint8_t r0 = clamp_8bit((YUV_MAT_Y * _y0 +                   YUV_MAT_V_R * v + YUV_OFFSET) >> YUV_SHIFT);
+         uint8_t g0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) >> YUV_SHIFT);
+         uint8_t b0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_B * u                   + YUV_OFFSET) >> YUV_SHIFT);
+
+         uint8_t r1 = clamp_8bit((YUV_MAT_Y * _y1 +                   YUV_MAT_V_R * v + YUV_OFFSET) >> YUV_SHIFT);
+         uint8_t g1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) >> YUV_SHIFT);
+         uint8_t b1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_B * u                   + YUV_OFFSET) >> YUV_SHIFT);
+
+         dst[0]     = 0xff000000u | (r0 << 16) | (g0 << 8) | (b0 << 0);
+         dst[1]     = 0xff000000u | (r1 << 16) | (g1 << 8) | (b1 << 0);
+      }
+   }
+}
+
+void conv_copy(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride)
+{
+   int h;
+   int copy_len         = abs(out_stride);
+   const uint8_t *input = (const uint8_t*)input_;
+   uint8_t *output      = (uint8_t*)output_;
+
+   if (abs(in_stride) < copy_len)
+      copy_len          = abs(in_stride);
+
+   for (h = 0; h < height;
+         h++, output += out_stride, input += in_stride)
+      memcpy(output, input, copy_len);
+}
diff --git a/deps/libretro-common/gfx/scaler/scaler.c b/deps/libretro-common/gfx/scaler/scaler.c
new file mode 100644 (file)
index 0000000..7c3c54e
--- /dev/null
@@ -0,0 +1,359 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (scaler.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <gfx/scaler/scaler.h>
+#include <gfx/scaler/scaler_int.h>
+#include <gfx/scaler/filter.h>
+#include <gfx/scaler/pixconv.h>
+
+static bool allocate_frames(struct scaler_ctx *ctx)
+{
+   uint64_t *scaled_frame = NULL;
+   ctx->scaled.stride     = ((ctx->out_width + 7) & ~7) * sizeof(uint64_t);
+   ctx->scaled.width      = ctx->out_width;
+   ctx->scaled.height     = ctx->in_height;
+   scaled_frame           = (uint64_t*)calloc(sizeof(uint64_t),
+            (ctx->scaled.stride * ctx->scaled.height) >> 3);
+
+   if (!scaled_frame)
+      return false;
+
+   ctx->scaled.frame      = scaled_frame;
+
+   if (ctx->in_fmt != SCALER_FMT_ARGB8888)
+   {
+      uint32_t *input_frame = NULL;
+      ctx->input.stride     = ((ctx->in_width + 7) & ~7) * sizeof(uint32_t);
+      input_frame           = (uint32_t*)calloc(sizeof(uint32_t),
+               (ctx->input.stride * ctx->in_height) >> 2);
+
+      if (!input_frame)
+         return false;
+
+      ctx->input.frame      = input_frame;
+   }
+
+   if (ctx->out_fmt != SCALER_FMT_ARGB8888)
+   {
+      uint32_t *output_frame = NULL;
+      ctx->output.stride     = ((ctx->out_width + 7) & ~7) * sizeof(uint32_t);
+
+      output_frame           = (uint32_t*)calloc(sizeof(uint32_t),
+               (ctx->output.stride * ctx->out_height) >> 2);
+
+      if (!output_frame)
+         return false;
+
+      ctx->output.frame      = output_frame;
+   }
+
+   return true;
+}
+
+bool scaler_ctx_gen_filter(struct scaler_ctx *ctx)
+{
+   scaler_ctx_gen_reset(ctx);
+
+   ctx->scaler_special = NULL;
+   ctx->unscaled       = false;
+
+   if (!allocate_frames(ctx))
+      return false;
+
+   if (     ctx->in_width  == ctx->out_width
+         && ctx->in_height == ctx->out_height)
+   {
+      ctx->unscaled     = true; /* Only pixel format conversion ... */
+
+      if (ctx->in_fmt == ctx->out_fmt)
+         ctx->direct_pixconv = conv_copy;
+      else
+      {
+         /* Bind a pixel converter callback function to the
+          * 'direct_pixconv' function pointer of the scaler context object. */
+         switch (ctx->in_fmt)
+         {
+            case SCALER_FMT_0RGB1555:
+               switch (ctx->out_fmt)
+               {
+                  case SCALER_FMT_ARGB8888:
+                     ctx->direct_pixconv = conv_0rgb1555_argb8888;
+                     break;
+                  case SCALER_FMT_RGB565:
+                     ctx->direct_pixconv = conv_0rgb1555_rgb565;
+                     break;
+                  case SCALER_FMT_BGR24:
+                     ctx->direct_pixconv = conv_0rgb1555_bgr24;
+                     break;
+                  default:
+                     break;
+               }
+               break;
+            case SCALER_FMT_RGB565:
+               switch (ctx->out_fmt)
+               {
+                  case SCALER_FMT_ARGB8888:
+                     ctx->direct_pixconv = conv_rgb565_argb8888;
+                     break;
+                  case SCALER_FMT_ABGR8888:
+                     ctx->direct_pixconv = conv_rgb565_abgr8888;
+                     break;
+                  case SCALER_FMT_BGR24:
+                     ctx->direct_pixconv = conv_rgb565_bgr24;
+                     break;
+                  case SCALER_FMT_0RGB1555:
+                     ctx->direct_pixconv = conv_rgb565_0rgb1555;
+                     break;
+                  default:
+                     break;
+               }
+               break;
+            case SCALER_FMT_BGR24:
+               switch (ctx->out_fmt)
+               {
+                  case SCALER_FMT_ARGB8888:
+                     ctx->direct_pixconv = conv_bgr24_argb8888;
+                     break;
+                  case SCALER_FMT_RGB565:
+                     ctx->direct_pixconv = conv_bgr24_rgb565;
+                  default:
+                     break;
+               }
+               break;
+            case SCALER_FMT_ARGB8888:
+               switch (ctx->out_fmt)
+               {
+                  case SCALER_FMT_0RGB1555:
+                     ctx->direct_pixconv = conv_argb8888_0rgb1555;
+                     break;
+                  case SCALER_FMT_BGR24:
+                     ctx->direct_pixconv = conv_argb8888_bgr24;
+                     break;
+                  case SCALER_FMT_ABGR8888:
+                     ctx->direct_pixconv = conv_argb8888_abgr8888;
+                     break;
+                  case SCALER_FMT_RGBA4444:
+                     ctx->direct_pixconv = conv_argb8888_rgba4444;
+                     break;
+                  default:
+                     break;
+               }
+               break;
+            case SCALER_FMT_YUYV:
+               switch (ctx->out_fmt)
+               {
+                  case SCALER_FMT_ARGB8888:
+                     ctx->direct_pixconv = conv_yuyv_argb8888;
+                     break;
+                  default:
+                     break;
+               }
+               break;
+            case SCALER_FMT_RGBA4444:
+               switch (ctx->out_fmt)
+               {
+                  case SCALER_FMT_ARGB8888:
+                     ctx->direct_pixconv = conv_rgba4444_argb8888;
+                     break;
+                  case SCALER_FMT_RGB565:
+                     ctx->direct_pixconv = conv_rgba4444_rgb565;
+                     break;
+                  default:
+                     break;
+               }
+               break;
+            case SCALER_FMT_ABGR8888:
+               switch (ctx->out_fmt)
+               {
+                  case SCALER_FMT_BGR24:
+                     ctx->direct_pixconv = conv_abgr8888_bgr24;
+                     break;
+                  default:
+                     break;
+               }
+               break;
+         }
+
+         if (!ctx->direct_pixconv)
+            return false;
+      }
+   }
+   else
+   {
+      ctx->scaler_horiz = scaler_argb8888_horiz;
+      ctx->scaler_vert  = scaler_argb8888_vert;
+
+      switch (ctx->in_fmt)
+      {
+         case SCALER_FMT_ARGB8888:
+            /* No need to convert :D */
+            break;
+
+         case SCALER_FMT_0RGB1555:
+            ctx->in_pixconv = conv_0rgb1555_argb8888;
+            break;
+
+         case SCALER_FMT_RGB565:
+            ctx->in_pixconv = conv_rgb565_argb8888;
+            break;
+
+         case SCALER_FMT_BGR24:
+            ctx->in_pixconv = conv_bgr24_argb8888;
+            break;
+
+         case SCALER_FMT_RGBA4444:
+            ctx->in_pixconv = conv_rgba4444_argb8888;
+            break;
+
+         default:
+            return false;
+      }
+
+      switch (ctx->out_fmt)
+      {
+         case SCALER_FMT_ARGB8888:
+            /* No need to convert :D */
+            break;
+
+         case SCALER_FMT_RGBA4444:
+            ctx->out_pixconv = conv_argb8888_rgba4444;
+            break;
+
+         case SCALER_FMT_0RGB1555:
+            ctx->out_pixconv = conv_argb8888_0rgb1555;
+            break;
+
+         case SCALER_FMT_BGR24:
+            ctx->out_pixconv = conv_argb8888_bgr24;
+            break;
+
+         case SCALER_FMT_ABGR8888:
+            ctx->out_pixconv = conv_argb8888_abgr8888;
+            break;
+
+         default:
+            return false;
+      }
+
+      if (!scaler_gen_filter(ctx))
+         return false;
+   }
+
+   return true;
+}
+
+void scaler_ctx_gen_reset(struct scaler_ctx *ctx)
+{
+   if (ctx->horiz.filter)
+      free(ctx->horiz.filter);
+   if (ctx->horiz.filter_pos)
+      free(ctx->horiz.filter_pos);
+   if (ctx->vert.filter)
+      free(ctx->vert.filter);
+   if (ctx->vert.filter_pos)
+      free(ctx->vert.filter_pos);
+   if (ctx->scaled.frame)
+      free(ctx->scaled.frame);
+   if (ctx->input.frame)
+      free(ctx->input.frame);
+   if (ctx->output.frame)
+      free(ctx->output.frame);
+
+   ctx->horiz.filter        = NULL;
+   ctx->horiz.filter_len    = 0;
+   ctx->horiz.filter_stride = 0;
+   ctx->horiz.filter_pos    = NULL;
+
+   ctx->vert.filter         = NULL;
+   ctx->vert.filter_len     = 0;
+   ctx->vert.filter_stride  = 0;
+   ctx->vert.filter_pos     = NULL;
+
+   ctx->scaled.frame        = NULL;
+   ctx->scaled.width        = 0;
+   ctx->scaled.height       = 0;
+   ctx->scaled.stride       = 0;
+
+   ctx->input.frame         = NULL;
+   ctx->input.stride        = 0;
+
+   ctx->output.frame        = NULL;
+   ctx->output.stride       = 0;
+}
+
+/**
+ * scaler_ctx_scale:
+ * @ctx          : pointer to scaler context object.
+ * @output       : pointer to output image.
+ * @input        : pointer to input image.
+ *
+ * Scales an input image to an output image.
+ **/
+void scaler_ctx_scale(struct scaler_ctx *ctx,
+      void *output, const void *input)
+{
+   const void *input_frame = input;
+   void *output_frame      = output;
+   int input_stride        = ctx->in_stride;
+   int output_stride       = ctx->out_stride;
+
+   if (ctx->in_fmt != SCALER_FMT_ARGB8888)
+   {
+      ctx->in_pixconv(ctx->input.frame, input,
+            ctx->in_width, ctx->in_height,
+            ctx->input.stride, ctx->in_stride);
+
+      input_frame       = ctx->input.frame;
+      input_stride      = ctx->input.stride;
+   }
+
+   if (ctx->out_fmt != SCALER_FMT_ARGB8888)
+   {
+      output_frame  = ctx->output.frame;
+      output_stride = ctx->output.stride;
+   }
+
+   /* Take some special, and (hopefully) more optimized path. */
+   if (ctx->scaler_special)
+      ctx->scaler_special(ctx, output_frame, input_frame,
+            ctx->out_width, ctx->out_height,
+            ctx->in_width, ctx->in_height,
+            output_stride, input_stride);
+   else
+   {
+      /* Take generic filter path. */
+      if (ctx->scaler_horiz)
+         ctx->scaler_horiz(ctx, input_frame, input_stride);
+      if (ctx->scaler_vert)
+         ctx->scaler_vert (ctx, output, output_stride);
+   }
+
+   if (ctx->out_fmt != SCALER_FMT_ARGB8888)
+      ctx->out_pixconv(output, ctx->output.frame,
+            ctx->out_width, ctx->out_height,
+            ctx->out_stride, ctx->output.stride);
+}
diff --git a/deps/libretro-common/gfx/scaler/scaler_filter.c b/deps/libretro-common/gfx/scaler/scaler_filter.c
new file mode 100644 (file)
index 0000000..a614290
--- /dev/null
@@ -0,0 +1,246 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (scaler_filter.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include <gfx/scaler/filter.h>
+#include <gfx/scaler/scaler_int.h>
+#include <retro_inline.h>
+#include <filters.h>
+#include <retro_math.h>
+
+#define FILTER_UNITY (1 << 14)
+
+static INLINE void gen_filter_point_sub(struct scaler_filter *filter,
+      int len, int pos, int step)
+{
+   int i;
+   for (i = 0; i < len; i++, pos += step)
+   {
+      filter->filter_pos[i] = pos >> 16;
+      filter->filter[i]     = FILTER_UNITY;
+   }
+}
+
+static INLINE void gen_filter_bilinear_sub(struct scaler_filter *filter,
+      int len, int pos, int step)
+{
+   int i;
+   for (i = 0; i < len; i++, pos += step)
+   {
+      filter->filter_pos[i]     = pos >> 16;
+      filter->filter[i * 2 + 1] = (pos & 0xffff) >> 2;
+      filter->filter[i * 2 + 0] = FILTER_UNITY - filter->filter[i * 2 + 1];
+   }
+}
+
+static INLINE void gen_filter_sinc_sub(struct scaler_filter *filter,
+      int len, int pos, int step, double phase_mul)
+{
+   int i, j;
+   const int sinc_size = filter->filter_len;
+
+   for (i = 0; i < len; i++, pos += step)
+   {
+      filter->filter_pos[i] = pos >> 16;
+
+      for (j = 0; j < sinc_size; j++)
+      {
+         double sinc_phase    = M_PI * ((double)((sinc_size << 15) + (pos & 0xffff)) / 0x10000 - j);
+         double lanczos_phase = sinc_phase / ((sinc_size >> 1));
+         int16_t sinc_val     = FILTER_UNITY * sinc(sinc_phase * phase_mul) * sinc(lanczos_phase) * phase_mul;
+
+         filter->filter[i * sinc_size + j] = sinc_val;
+      }
+   }
+}
+
+static bool validate_filter(struct scaler_ctx *ctx)
+{
+   int i;
+   int max_h_pos;
+   int max_w_pos = ctx->in_width - ctx->horiz.filter_len;
+
+   for (i = 0; i < ctx->out_width; i++)
+   {
+      if (ctx->horiz.filter_pos[i] > max_w_pos || ctx->horiz.filter_pos[i] < 0)
+      {
+#ifndef NDEBUG
+         fprintf(stderr, "Out X = %d => In X = %d\n", i, ctx->horiz.filter_pos[i]);
+#endif
+         return false;
+      }
+   }
+
+   max_h_pos = ctx->in_height - ctx->vert.filter_len;
+
+   for (i = 0; i < ctx->out_height; i++)
+   {
+      if (ctx->vert.filter_pos[i] > max_h_pos || ctx->vert.filter_pos[i] < 0)
+      {
+#ifndef NDEBUG
+         fprintf(stderr, "Out Y = %d => In Y = %d\n", i, ctx->vert.filter_pos[i]);
+#endif
+         return false;
+      }
+   }
+
+   return true;
+}
+
+static void fixup_filter_sub(struct scaler_filter *filter,
+      int out_len, int in_len)
+{
+   int i;
+   int max_pos = in_len - filter->filter_len;
+
+   for (i = 0; i < out_len; i++)
+   {
+      int postsample =  filter->filter_pos[i] - max_pos;
+      int presample  = -filter->filter_pos[i];
+
+      if (postsample > 0)
+      {
+         int16_t *base_filter   = NULL;
+
+         filter->filter_pos[i] -= postsample;
+
+         base_filter            = filter->filter + i * filter->filter_stride;
+
+         if (postsample > (int)filter->filter_len)
+            memset(base_filter, 0, filter->filter_len * sizeof(int16_t));
+         else
+         {
+            memmove(base_filter + postsample, base_filter,
+                  (filter->filter_len - postsample) * sizeof(int16_t));
+            memset(base_filter, 0, postsample * sizeof(int16_t));
+         }
+      }
+
+      if (presample > 0)
+      {
+         int16_t *base_filter   = NULL;
+
+         filter->filter_pos[i] += presample;
+         base_filter            = filter->filter + i * filter->filter_stride;
+
+         if (presample > (int)filter->filter_len)
+            memset(base_filter, 0, filter->filter_len * sizeof(int16_t));
+         else
+         {
+            memmove(base_filter, base_filter + presample,
+                  (filter->filter_len - presample) * sizeof(int16_t));
+            memset(base_filter + (filter->filter_len - presample),
+                  0, presample * sizeof(int16_t));
+         }
+      }
+   }
+}
+
+bool scaler_gen_filter(struct scaler_ctx *ctx)
+{
+   int x_pos, x_step, y_pos, y_step;
+   int sinc_size = 0;
+
+   switch (ctx->scaler_type)
+   {
+      case SCALER_TYPE_POINT:
+         ctx->horiz.filter_len    = 1;
+         ctx->horiz.filter_stride = 1;
+         ctx->vert.filter_len     = 1;
+         ctx->vert.filter_stride  = 1;
+         break;
+      case SCALER_TYPE_BILINEAR:
+         ctx->horiz.filter_len    = 2;
+         ctx->horiz.filter_stride = 2;
+         ctx->vert.filter_len     = 2;
+         ctx->vert.filter_stride  = 2;
+         break;
+      case SCALER_TYPE_SINC:
+         sinc_size                = 8 * ((ctx->in_width > ctx->out_width)
+               ? next_pow2(ctx->in_width / ctx->out_width) : 1);
+         ctx->horiz.filter_len    = sinc_size;
+         ctx->horiz.filter_stride = sinc_size;
+         ctx->vert.filter_len     = sinc_size;
+         ctx->vert.filter_stride  = sinc_size;
+         break;
+      case SCALER_TYPE_UNKNOWN:
+      default:
+         return false;
+   }
+
+   ctx->horiz.filter     = (int16_t*)calloc(sizeof(int16_t), ctx->horiz.filter_stride * ctx->out_width);
+   ctx->horiz.filter_pos = (int*)calloc(sizeof(int), ctx->out_width);
+
+   ctx->vert.filter      = (int16_t*)calloc(sizeof(int16_t), ctx->vert.filter_stride * ctx->out_height);
+   ctx->vert.filter_pos  = (int*)calloc(sizeof(int), ctx->out_height);
+
+   if (!ctx->horiz.filter || !ctx->vert.filter)
+      return false;
+
+   x_step = (1 << 16) * ctx->in_width / ctx->out_width;
+   y_step = (1 << 16) * ctx->in_height / ctx->out_height;
+
+   switch (ctx->scaler_type)
+   {
+      case SCALER_TYPE_POINT:
+         x_pos  = (1 << 15) * ctx->in_width / ctx->out_width   - (1 << 15);
+         y_pos  = (1 << 15) * ctx->in_height / ctx->out_height - (1 << 15);
+
+         gen_filter_point_sub(&ctx->horiz, ctx->out_width,  x_pos, x_step);
+         gen_filter_point_sub(&ctx->vert,  ctx->out_height, y_pos, y_step);
+
+         ctx->scaler_special = scaler_argb8888_point_special;
+         break;
+
+      case SCALER_TYPE_BILINEAR:
+         x_pos  = (1 << 15) * ctx->in_width / ctx->out_width   - (1 << 15);
+         y_pos  = (1 << 15) * ctx->in_height / ctx->out_height - (1 << 15);
+
+         gen_filter_bilinear_sub(&ctx->horiz, ctx->out_width,  x_pos, x_step);
+         gen_filter_bilinear_sub(&ctx->vert,  ctx->out_height, y_pos, y_step);
+         break;
+
+      case SCALER_TYPE_SINC:
+         /* Need to expand the filter when downsampling
+          * to get a proper low-pass effect. */
+
+         x_pos  = (1 << 15) * ctx->in_width  / ctx->out_width  - (1 << 15) - (sinc_size << 15);
+         y_pos  = (1 << 15) * ctx->in_height / ctx->out_height - (1 << 15) - (sinc_size << 15);
+
+         gen_filter_sinc_sub(&ctx->horiz, ctx->out_width, x_pos, x_step,
+               ctx->in_width  > ctx->out_width  ? (double)ctx->out_width  / ctx->in_width  : 1.0);
+         gen_filter_sinc_sub(&ctx->vert, ctx->out_height, y_pos, y_step,
+               ctx->in_height > ctx->out_height ? (double)ctx->out_height / ctx->in_height : 1.0
+               );
+         break;
+      case SCALER_TYPE_UNKNOWN:
+         break;
+   }
+
+   /* Makes sure that we never sample outside our rectangle. */
+   fixup_filter_sub(&ctx->horiz, ctx->out_width, ctx->in_width);
+   fixup_filter_sub(&ctx->vert,  ctx->out_height, ctx->in_height);
+
+   return validate_filter(ctx);
+}
diff --git a/deps/libretro-common/gfx/scaler/scaler_int.c b/deps/libretro-common/gfx/scaler/scaler_int.c
new file mode 100644 (file)
index 0000000..3c659e1
--- /dev/null
@@ -0,0 +1,261 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (scaler_int.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <gfx/scaler/scaler_int.h>
+
+#include <retro_inline.h>
+
+#ifdef SCALER_NO_SIMD
+#undef __SSE2__
+#endif
+
+#if defined(__SSE2__)
+#include <emmintrin.h>
+#ifdef _WIN32
+#include <intrin.h>
+#endif
+#endif
+
+/* ARGB8888 scaler is split in two:
+ *
+ * First, horizontal scaler is applied.
+ * Here, all 8-bit channels are expanded to 16-bit. Values are then shifted 7
+ * to left to occupy 15 bits.
+ *
+ * The sign bit is kept empty as we have to do signed multiplication for the
+ * filter.
+ *
+ * A mulhi [(a * b) >> 16] is applied which loses some precision, but is
+ * very efficient for SIMD.
+ * It is accurate enough for 8-bit purposes.
+ *
+ * The fixed point 1.0 for filter is (1 << 14). After horizontal scale,
+ * the output is kept with 16-bit channels, and will now have 13 bits
+ * of precision as [(a * (1 << 14)) >> 16] is effectively a right shift by 2.
+ *
+ * Vertical scaler takes the 13 bit channels, and performs the
+ * same mulhi steps.
+ * Another 2 bits of precision is lost, which ends up as 11 bits.
+ * Scaling is now complete. Channels are shifted right by 3, and saturated
+ * into 8-bit values.
+ *
+ * The C version of scalers perform the exact same operations as the
+ * SIMD code for testing purposes.
+ */
+
+void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)
+{
+   int h, w, y;
+   const uint64_t      *input = ctx->scaled.frame;
+   uint32_t           *output = (uint32_t*)output_;
+
+   const int16_t *filter_vert = ctx->vert.filter;
+
+   for (h = 0; h < ctx->out_height; h++,
+         filter_vert += ctx->vert.filter_stride, output += stride >> 2)
+   {
+      const uint64_t *input_base = input + ctx->vert.filter_pos[h]
+         * (ctx->scaled.stride >> 3);
+
+      for (w = 0; w < ctx->out_width; w++)
+      {
+         const uint64_t *input_base_y = input_base + w;
+#if defined(__SSE2__)
+         __m128i final;
+         __m128i res = _mm_setzero_si128();
+
+         for (y = 0; (y + 1) < ctx->vert.filter_len; y += 2,
+               input_base_y += (ctx->scaled.stride >> 2))
+         {
+            __m128i coeff = _mm_set_epi64x(filter_vert[y + 1] * 0x0001000100010001ll, filter_vert[y + 0] * 0x0001000100010001ll);
+            __m128i col   = _mm_set_epi64x(input_base_y[ctx->scaled.stride >> 3], input_base_y[0]);
+
+            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+         }
+
+         for (; y < ctx->vert.filter_len; y++, input_base_y += (ctx->scaled.stride >> 3))
+         {
+            __m128i coeff = _mm_set_epi64x(0, filter_vert[y] * 0x0001000100010001ll);
+            __m128i col   = _mm_set_epi64x(0, input_base_y[0]);
+
+            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+         }
+
+         res       = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
+         res       = _mm_srai_epi16(res, (7 - 2 - 2));
+
+         final     = _mm_packus_epi16(res, res);
+
+         output[w] = _mm_cvtsi128_si32(final);
+#else
+         int16_t res_a = 0;
+         int16_t res_r = 0;
+         int16_t res_g = 0;
+         int16_t res_b = 0;
+
+         for (y = 0; y < ctx->vert.filter_len; y++,
+               input_base_y += (ctx->scaled.stride >> 3))
+         {
+            uint64_t col   = *input_base_y;
+
+            int16_t a      = (col >> 48) & 0xffff;
+            int16_t r      = (col >> 32) & 0xffff;
+            int16_t g      = (col >> 16) & 0xffff;
+            int16_t b      = (col >>  0) & 0xffff;
+
+            int16_t coeff  = filter_vert[y];
+
+            res_a         += (a * coeff) >> 16;
+            res_r         += (r * coeff) >> 16;
+            res_g         += (g * coeff) >> 16;
+            res_b         += (b * coeff) >> 16;
+         }
+
+         res_a           >>= (7 - 2 - 2);
+         res_r           >>= (7 - 2 - 2);
+         res_g           >>= (7 - 2 - 2);
+         res_b           >>= (7 - 2 - 2);
+
+         output[w]         =
+            (clamp_8bit(res_a) << 24) |
+            (clamp_8bit(res_r) << 16) |
+            (clamp_8bit(res_g) << 8)  |
+            (clamp_8bit(res_b) << 0);
+#endif
+      }
+   }
+}
+
+void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)
+{
+   int h, w, x;
+   const uint32_t *input = (uint32_t*)input_;
+   uint64_t *output      = ctx->scaled.frame;
+
+   for (h = 0; h < ctx->scaled.height; h++, input += stride >> 2,
+         output += ctx->scaled.stride >> 3)
+   {
+      const int16_t *filter_horiz = ctx->horiz.filter;
+
+      for (w = 0; w < ctx->scaled.width; w++,
+            filter_horiz += ctx->horiz.filter_stride)
+      {
+         const uint32_t *input_base_x = input + ctx->horiz.filter_pos[w];
+#if defined(__SSE2__)
+         __m128i res = _mm_setzero_si128();
+#ifndef __x86_64__
+         union
+         {
+            uint32_t *u32;
+            uint64_t *u64;
+         } u;
+#endif
+         for (x = 0; (x + 1) < ctx->horiz.filter_len; x += 2)
+         {
+            __m128i coeff = _mm_set_epi64x(filter_horiz[x + 1] * 0x0001000100010001ll, filter_horiz[x + 0] * 0x0001000100010001ll);
+
+            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi64x(0,
+                     ((uint64_t)input_base_x[x + 1] << 32) | input_base_x[x + 0]), _mm_setzero_si128());
+
+            col           = _mm_slli_epi16(col, 7);
+            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+         }
+
+         for (; x < ctx->horiz.filter_len; x++)
+         {
+            __m128i coeff = _mm_set_epi64x(0, filter_horiz[x] * 0x0001000100010001ll);
+            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi32(0, 0, 0, input_base_x[x]), _mm_setzero_si128());
+
+            col           = _mm_slli_epi16(col, 7);
+            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+         }
+
+         res              = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
+
+#ifdef __x86_64__
+         output[w]        = _mm_cvtsi128_si64(res);
+#else /* 32-bit doesn't have si64. Do it in two steps. */
+         u.u64    = output + w;
+         u.u32[0] = _mm_cvtsi128_si32(res);
+         u.u32[1] = _mm_cvtsi128_si32(_mm_srli_si128(res, 4));
+#endif
+#else
+         int16_t res_a = 0;
+         int16_t res_r = 0;
+         int16_t res_g = 0;
+         int16_t res_b = 0;
+
+         for (x = 0; x < ctx->horiz.filter_len; x++)
+         {
+            uint32_t col   = input_base_x[x];
+
+            int16_t a      = (col >> (24 - 7)) & (0xff << 7);
+            int16_t r      = (col >> (16 - 7)) & (0xff << 7);
+            int16_t g      = (col >> ( 8 - 7)) & (0xff << 7);
+            int16_t b      = (col << ( 0 + 7)) & (0xff << 7);
+
+            int16_t coeff  = filter_horiz[x];
+
+            res_a         += (a * coeff) >> 16;
+            res_r         += (r * coeff) >> 16;
+            res_g         += (g * coeff) >> 16;
+            res_b         += (b * coeff) >> 16;
+         }
+
+         output[w]         = (
+               (uint64_t)res_a  << 48)  |
+               ((uint64_t)res_r << 32)  |
+               ((uint64_t)res_g << 16)  |
+               ((uint64_t)res_b << 0);
+#endif
+      }
+   }
+}
+
+void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
+      void *output_, const void *input_,
+      int out_width, int out_height,
+      int in_width, int in_height,
+      int out_stride, int in_stride)
+{
+   int h, w;
+   int x_pos             = (1 << 15) * in_width / out_width - (1 << 15);
+   int x_step            = (1 << 16) * in_width / out_width;
+   int y_pos             = (1 << 15) * in_height / out_height - (1 << 15);
+   int y_step            = (1 << 16) * in_height / out_height;
+   const uint32_t *input = (const uint32_t*)input_;
+   uint32_t *output      = (uint32_t*)output_;
+
+   if (x_pos < 0)
+      x_pos = 0;
+   if (y_pos < 0)
+      y_pos = 0;
+
+   for (h = 0; h < out_height; h++, y_pos += y_step, output += out_stride >> 2)
+   {
+      int               x = x_pos;
+      const uint32_t *inp = input + (y_pos >> 16) * (in_stride >> 2);
+
+      for (w = 0; w < out_width; w++, x += x_step)
+         output[w] = inp[x >> 16];
+   }
+}
diff --git a/deps/libretro-common/glsm/glsm.c b/deps/libretro-common/glsm/glsm.c
new file mode 100644 (file)
index 0000000..8b08c57
--- /dev/null
@@ -0,0 +1,2897 @@
+/* Copyright (C) 2010-2018 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsm).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <glsym/glsym.h>
+#include <glsm/glsm.h>
+
+#ifndef GL_DEPTH_CLAMP
+#define GL_DEPTH_CLAMP                    0x864F
+#define GL_RASTERIZER_DISCARD             0x8C89
+#define GL_SAMPLE_MASK                    0x8E51
+#endif
+
+#if 0
+extern retro_log_printf_t log_cb;
+#define GLSM_DEBUG
+#endif
+
+struct gl_cached_state
+{
+   struct
+   {
+      GLuint *ids;
+   } bind_textures;
+
+   struct
+   {
+      bool used[MAX_ATTRIB];
+      GLint size[MAX_ATTRIB];
+      GLenum type[MAX_ATTRIB];
+      GLboolean normalized[MAX_ATTRIB];
+      GLsizei stride[MAX_ATTRIB];
+      const GLvoid *pointer[MAX_ATTRIB];
+      GLuint buffer[MAX_ATTRIB];
+   } attrib_pointer;
+
+#ifndef HAVE_OPENGLES
+   GLenum colorlogicop;
+#endif
+
+   struct
+   {
+      bool enabled[MAX_ATTRIB];
+   } vertex_attrib_pointer;
+
+   struct
+   {
+      GLenum pname;
+      GLint param;
+   } pixelstore_i;
+
+   struct
+   {
+      GLuint r;
+      GLuint g;
+      GLuint b;
+      GLuint a;
+   } clear_color;
+
+   struct
+   {
+      bool used;
+      GLint x;
+      GLint y;
+      GLsizei w;
+      GLsizei h;
+   } scissor;
+
+   struct
+   {
+      GLint x;
+      GLint y;
+      GLsizei w;
+      GLsizei h;
+   } viewport;
+
+   struct
+   {
+      bool used;
+      GLenum sfactor;
+      GLenum dfactor;
+   } blendfunc;
+
+   struct
+   {
+      bool used;
+      GLenum srcRGB;
+      GLenum dstRGB;
+      GLenum srcAlpha;
+      GLenum dstAlpha;
+   } blendfunc_separate;
+
+   struct
+   {
+      bool used;
+      GLboolean red;
+      GLboolean green;
+      GLboolean blue;
+      GLboolean alpha;
+   } colormask;
+
+   struct
+   {
+      bool used;
+      GLdouble depth;
+   } cleardepth;
+
+   struct
+   {
+      bool used;
+      GLenum func;
+   } depthfunc;
+
+   struct
+   {
+      bool used;
+      GLclampd zNear;
+      GLclampd zFar;
+   } depthrange;
+
+   struct
+   {
+      bool used;
+      GLfloat factor;
+      GLfloat units;
+   } polygonoffset;
+
+   struct
+   {
+      bool used;
+      GLenum func;
+      GLint ref;
+      GLuint mask;
+   } stencilfunc;
+
+   struct
+   {
+      bool used;
+      GLenum sfail;
+      GLenum dpfail;
+      GLenum dppass;
+   } stencilop;
+
+   struct
+   {
+      bool used;
+      GLenum mode;
+   } frontface;
+
+   struct
+   {
+      bool used;
+      GLenum mode;
+   } cullface;
+
+   struct
+   {
+      bool used;
+      GLuint mask;
+   } stencilmask;
+
+   struct
+   {
+      bool used;
+      GLboolean mask;
+   } depthmask;
+
+   struct
+   {
+      GLenum mode;
+   } readbuffer;
+
+   GLuint vao;
+   GLuint framebuf;
+   GLuint array_buffer;
+   GLuint program;
+   GLenum active_texture;
+   int cap_state[SGL_CAP_MAX];
+   int cap_translate[SGL_CAP_MAX];
+};
+
+static GLuint default_framebuffer;
+static GLint glsm_max_textures;
+struct retro_hw_render_callback hw_render;
+static struct gl_cached_state gl_state;
+
+/* GL wrapper-side */
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+GLenum rglGetError(void)
+{
+   return glGetError();
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : N/A
+ */
+
+void rglProvokingVertex(       GLenum provokeMode)
+{
+#if defined(HAVE_OPENGL)
+   glProvokingVertex(provokeMode);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : 3.0
+ */
+void rglGetInteger64v( GLenum pname, int64_t *data)
+{
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGetInteger64v(pname, (GLint64*)data);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : 3.0
+ */
+void rglSamplerParameteri(     GLuint sampler,
+       GLenum pname,
+       GLint param)
+{
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glSamplerParameteri(sampler, pname, param);
+#endif
+}
+
+void rglGenSamplers(   GLsizei n,
+       GLuint *samplers)
+{
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGenSamplers(n, samplers);
+#endif
+}
+
+void rglBindSampler(   GLuint unit,
+       GLuint sampler)
+{
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glBindSampler(unit, sampler);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglClear(GLbitfield mask)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glClear.\n");
+#endif
+   glClear(mask);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglValidateProgram(GLuint program)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glValidateProgram.\n");
+#endif
+   glValidateProgram(program);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ * OpenGLES  : N/A
+ */
+void rglPolygonMode(GLenum face, GLenum mode)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glPolygonMode.\n");
+#endif
+#ifndef HAVE_OPENGLES
+   glPolygonMode(face, mode);
+#endif
+}
+
+void rglTexSubImage2D(
+      GLenum target,
+       GLint level,
+       GLint xoffset,
+       GLint yoffset,
+       GLsizei width,
+       GLsizei height,
+       GLenum format,
+       GLenum type,
+       const GLvoid * pixels)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTexSubImage2D.\n");
+#endif
+   glTexSubImage2D(target, level, xoffset, yoffset,
+         width, height, format, type, pixels);
+}
+
+void rglGetBufferSubData(      GLenum target,
+       GLintptr offset,
+       GLsizeiptr size,
+       GLvoid * data)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetBufferSubData.\n");
+#endif
+#if defined(HAVE_OPENGL)
+   glGetBufferSubData(target, offset, size, data);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglLineWidth(GLfloat width)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glLineWidth.\n");
+#endif
+   glLineWidth(width);
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 3.0
+ */
+void rglBlitFramebuffer(
+      GLint srcX0, GLint srcY0,
+      GLint srcX1, GLint srcY1,
+      GLint dstX0, GLint dstY0,
+      GLint dstX1, GLint dstY1,
+      GLbitfield mask, GLenum filter)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBlitFramebuffer.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
+         dstX0, dstY0, dstX1, dstY1,
+         mask, filter);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 3.0
+ */
+void rglReadBuffer(GLenum mode)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glReadBuffer.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glReadBuffer(mode);
+   gl_state.readbuffer.mode = mode;
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglClearDepth(GLdouble depth)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glClearDepth.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+#ifdef HAVE_OPENGLES
+   glClearDepthf(depth);
+#else
+   glClearDepth(depth);
+#endif
+   gl_state.cleardepth.used  = true;
+   gl_state.cleardepth.depth = depth;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglPixelStorei(GLenum pname, GLint param)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glPixelStorei.\n");
+#endif
+   glPixelStorei(pname, param);
+   gl_state.pixelstore_i.pname = pname;
+   gl_state.pixelstore_i.param = param;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglDepthRange(GLclampd zNear, GLclampd zFar)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDepthRange.\n");
+#endif
+#ifdef HAVE_OPENGLES
+   glDepthRangef(zNear, zFar);
+#else
+   glDepthRange(zNear, zFar);
+#endif
+   gl_state.depthrange.used  = true;
+   gl_state.depthrange.zNear = zNear;
+   gl_state.depthrange.zFar  = zFar;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglFrontFace(GLenum mode)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glFrontFace.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glFrontFace(mode);
+   gl_state.frontface.used = true;
+   gl_state.frontface.mode = mode;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglDepthFunc(GLenum func)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDepthFunc.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   gl_state.depthfunc.used = true;
+   gl_state.depthfunc.func = func;
+   glDepthFunc(func);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglColorMask(GLboolean red, GLboolean green,
+      GLboolean blue, GLboolean alpha)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glColorMask.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glColorMask(red, green, blue, alpha);
+   gl_state.colormask.red   = red;
+   gl_state.colormask.green = green;
+   gl_state.colormask.blue  = blue;
+   gl_state.colormask.alpha = alpha;
+   gl_state.colormask.used  = true;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglCullFace(GLenum mode)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glCullFace.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glCullFace(mode);
+   gl_state.cullface.used = true;
+   gl_state.cullface.mode = mode;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glStencilOp.\n");
+#endif
+   glStencilOp(sfail, dpfail, dppass);
+   gl_state.stencilop.used   = true;
+   gl_state.stencilop.sfail  = sfail;
+   gl_state.stencilop.dpfail = dpfail;
+   gl_state.stencilop.dppass = dppass;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 2.0
+ */
+void rglStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glStencilFunc.\n");
+#endif
+   glStencilFunc(func, ref, mask);
+   gl_state.stencilfunc.used = true;
+   gl_state.stencilfunc.func = func;
+   gl_state.stencilfunc.ref  = ref;
+   gl_state.stencilfunc.mask = mask;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+GLboolean rglIsEnabled(GLenum cap)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glIsEnabled.\n");
+#endif
+   return gl_state.cap_state[cap] ? GL_TRUE : GL_FALSE;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglClearColor(GLclampf red, GLclampf green,
+      GLclampf blue, GLclampf alpha)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glClearColor.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glClearColor(red, green, blue, alpha);
+   gl_state.clear_color.r = red;
+   gl_state.clear_color.g = green;
+   gl_state.clear_color.b = blue;
+   gl_state.clear_color.a = alpha;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES    : 2.0 (maybe earlier?)
+ */
+void rglScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glScissor.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glScissor(x, y, width, height);
+   gl_state.scissor.used = true;
+   gl_state.scissor.x    = x;
+   gl_state.scissor.y    = y;
+   gl_state.scissor.w    = width;
+   gl_state.scissor.h    = height;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glViewport.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glViewport(x, y, width, height);
+   gl_state.viewport.x = x;
+   gl_state.viewport.y = y;
+   gl_state.viewport.w = width;
+   gl_state.viewport.h = height;
+}
+
+void rglBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBlendFunc.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   gl_state.blendfunc.used    = true;
+   gl_state.blendfunc.sfactor = sfactor;
+   gl_state.blendfunc.dfactor = dfactor;
+   glBlendFunc(sfactor, dfactor);
+}
+
+/*
+ * Category: Blending
+ *
+ * Core in:
+ * OpenGL    : 1.4
+ */
+void rglBlendFuncSeparate(GLenum sfactor, GLenum dfactor)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBlendFuncSeparate.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   gl_state.blendfunc_separate.used     = true;
+   gl_state.blendfunc_separate.srcRGB   = sfactor;
+   gl_state.blendfunc_separate.dstRGB   = dfactor;
+   gl_state.blendfunc_separate.srcAlpha = sfactor;
+   gl_state.blendfunc_separate.dstAlpha = dfactor;
+   glBlendFunc(sfactor, dfactor);
+}
+
+/*
+ * Category: Textures
+ *
+ * Core in:
+ * OpenGL    : 1.3
+ */
+void rglActiveTexture(GLenum texture)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glActiveTexture.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glActiveTexture(texture);
+   gl_state.active_texture = texture - GL_TEXTURE0;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.1
+ */
+void rglBindTexture(GLenum target, GLuint texture)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindTexture.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glBindTexture(target, texture);
+   gl_state.bind_textures.ids[gl_state.active_texture] = texture;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglDisable(GLenum cap)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDisable.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glDisable(gl_state.cap_translate[cap]);
+   gl_state.cap_state[cap] = 0;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglEnable(GLenum cap)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glEnable.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glEnable(gl_state.cap_translate[cap]);
+   gl_state.cap_state[cap] = 1;
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUseProgram(GLuint program)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUseProgram.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   gl_state.program = program;
+   glUseProgram(program);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglDepthMask(GLboolean flag)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDepthMask.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glDepthMask(flag);
+   gl_state.depthmask.used = true;
+   gl_state.depthmask.mask = flag;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglStencilMask(GLenum mask)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glStencilMask.\n");
+#endif
+   glStencilMask(mask);
+   gl_state.stencilmask.used = true;
+   gl_state.stencilmask.mask = mask;
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.5
+ */
+void rglBufferData(GLenum target, GLsizeiptr size,
+      const GLvoid *data, GLenum usage)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBufferData.\n");
+#endif
+   glBufferData(target, size, data, usage);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.5
+ */
+void rglBufferSubData(GLenum target, GLintptr offset,
+      GLsizeiptr size, const GLvoid *data)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBufferSubData.\n");
+#endif
+   glBufferSubData(target, offset, size, data);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.5
+ */
+void rglBindBuffer(GLenum target, GLuint buffer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindBuffer.\n");
+#endif
+   if (target == GL_ARRAY_BUFFER)
+      gl_state.array_buffer = buffer;
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glBindBuffer(target, buffer);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglLinkProgram(GLuint program)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glLinkProgram.\n");
+#endif
+   glLinkProgram(program);
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 2.0
+ */
+void rglFramebufferTexture2D(GLenum target, GLenum attachment,
+      GLenum textarget, GLuint texture, GLint level)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glFramebufferTexture2D.\n");
+#endif
+   glFramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 3.2
+ */
+void rglFramebufferTexture(GLenum target, GLenum attachment,
+       GLuint texture, GLint level)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glFramebufferTexture.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
+   glFramebufferTexture(target, attachment, texture, level);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.1
+ */
+void rglDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDrawArrays.\n");
+#endif
+   glDrawArrays(mode, first, count);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.1
+ */
+void rglDrawElements(GLenum mode, GLsizei count, GLenum type,
+                           const GLvoid * indices)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDrawElements.\n");
+#endif
+   glDrawElements(mode, count, type, indices);
+}
+
+void rglCompressedTexImage2D(GLenum target, GLint level,
+      GLenum internalformat, GLsizei width, GLsizei height,
+      GLint border, GLsizei imageSize, const GLvoid *data)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glCompressedTexImage2D.\n");
+#endif
+   glCompressedTexImage2D(target, level, internalformat,
+         width, height, border, imageSize, data);
+}
+
+void rglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteFramebuffers.\n");
+#endif
+   glDeleteFramebuffers(n, framebuffers);
+}
+
+void rglDeleteTextures(GLsizei n, const GLuint *textures)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteTextures.\n");
+#endif
+   glDeleteTextures(n, textures);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES    : 2.0
+ */
+void rglRenderbufferStorage(GLenum target, GLenum internalFormat,
+      GLsizei width, GLsizei height)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glRenderbufferStorage.\n");
+#endif
+   glRenderbufferStorage(target, internalFormat, width, height);
+}
+
+/*
+ *
+ * Core in:
+ *
+ * OpenGL      : 3.0
+ * OpenGLES    : 2.0
+ */
+void rglBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindRenderbuffer.\n");
+#endif
+   glBindRenderbuffer(target, renderbuffer);
+}
+
+/*
+ *
+ * Core in:
+ *
+ * OpenGLES    : 2.0
+ */
+void rglDeleteRenderbuffers(GLsizei n, GLuint *renderbuffers)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteRenderbuffers.\n");
+#endif
+   glDeleteRenderbuffers(n, renderbuffers);
+}
+
+/*
+ *
+ * Core in:
+ *
+ * OpenGL      : 3.0
+ * OpenGLES    : 2.0
+ */
+void rglGenRenderbuffers(GLsizei n, GLuint *renderbuffers)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGenRenderbuffers.\n");
+#endif
+   glGenRenderbuffers(n, renderbuffers);
+}
+
+/*
+ *
+ * Core in:
+ *
+ * OpenGL      : 3.0
+ * OpenGLES    : 2.0
+ */
+void rglGenerateMipmap(GLenum target)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGenerateMipmap.\n");
+#endif
+   glGenerateMipmap(target);
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ */
+GLenum rglCheckFramebufferStatus(GLenum target)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glCheckFramebufferStatus.\n");
+#endif
+   return glCheckFramebufferStatus(target);
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 2.0
+ */
+void rglFramebufferRenderbuffer(GLenum target, GLenum attachment,
+      GLenum renderbuffertarget, GLuint renderbuffer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glFramebufferRenderbuffer.\n");
+#endif
+   glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ */
+void rglBindFragDataLocation(GLuint program, GLuint colorNumber,
+                                   const char * name)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindFragDataLocation.\n");
+#endif
+#if !defined(HAVE_OPENGLES2)
+   glBindFragDataLocation(program, colorNumber, name);
+#endif
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglGetProgramiv(GLuint shader, GLenum pname, GLint *params)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetProgramiv.\n");
+#endif
+   glGetProgramiv(shader, pname, params);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 4.1
+ * OpenGLES  : 3.0
+ */
+void rglProgramParameteri(     GLuint program,
+       GLenum pname,
+       GLint value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glProgramParameteri.\n");
+#endif
+#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && (defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1))
+   glProgramParameteri(program, pname, value);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
+      GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetActiveUniform.\n");
+#endif
+   glGetActiveUniform(program, index, bufsize, length, size, type, name);
+}
+
+void rglGenQueries(    GLsizei n,
+       GLuint * ids)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGenQueries.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGenQueries(n, ids);
+#endif
+}
+
+void rglGetQueryObjectuiv(     GLuint id,
+       GLenum pname,
+       GLuint * params)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetQueryObjectuiv.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGetQueryObjectuiv(id, pname, params);
+#endif
+}
+
+void rglDeleteQueries( GLsizei n,
+       const GLuint * ids)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteQueries.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glDeleteQueries(n, ids);
+#endif
+}
+
+void rglBeginQuery(    GLenum target,
+       GLuint id)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBeginQuery.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glBeginQuery(target, id);
+#endif
+}
+
+void rglEndQuery(      GLenum target)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glEndQuery.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glEndQuery(target);
+#endif
+}
+
+/*
+ * Category: UBO
+ *
+ * Core in:
+ *
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+void rglGetActiveUniformBlockiv(GLuint program,
+       GLuint uniformBlockIndex,
+       GLenum pname,
+       GLint *params)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetActiveUniformBlockiv.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGetActiveUniformBlockiv(program, uniformBlockIndex,
+         pname, params);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Core in:
+ *
+ * OpenGLES  : 3.0
+ */
+void rglGetActiveUniformsiv(   GLuint program,
+       GLsizei uniformCount,
+       const GLuint *uniformIndices,
+       GLenum pname,
+       GLint *params)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetActiveUniformsiv.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGetActiveUniformsiv(program, uniformCount,
+         uniformIndices, pname, params);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Core in:
+ *
+ * OpenGLES  : 3.0
+ */
+void rglGetUniformIndices(GLuint program,
+       GLsizei uniformCount,
+       const GLchar **uniformNames,
+       GLuint *uniformIndices)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetUniformIndices.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGetUniformIndices(program, uniformCount,
+         uniformNames, uniformIndices);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ * Category: UBO
+ *
+ * Core in:
+ *
+ * OpenGLES  : 3.0
+ */
+void rglBindBufferBase(        GLenum target,
+       GLuint index,
+       GLuint buffer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindBufferBase.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glBindBufferBase(target, index, buffer);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Category: UBO
+ *
+ * Core in:
+ *
+ * OpenGLES  : 3.0
+ */
+GLuint rglGetUniformBlockIndex(        GLuint program,
+       const GLchar *uniformBlockName)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetUniformBlockIndex.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   return glGetUniformBlockIndex(program, uniformBlockName);
+#else
+   printf("WARNING! Not implemented.\n");
+   return 0;
+#endif
+}
+
+/*
+ * Category: UBO
+ *
+ * Core in:
+ *
+ * OpenGLES  : 3.0
+ */
+void rglUniformBlockBinding(   GLuint program,
+       GLuint uniformBlockIndex,
+       GLuint uniformBlockBinding)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniformBlockBinding.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glUniformBlockBinding(program, uniformBlockIndex,
+         uniformBlockBinding);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+void rglUniform1ui(GLint location, GLuint v)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform1ui.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glUniform1ui(location ,v);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+void rglUniform2ui(GLint location, GLuint v0, GLuint v1)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform2ui.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glUniform2ui(location, v0, v1);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+void rglUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform3ui.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glUniform3ui(location, v0, v1, v2);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+void rglUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform4ui.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glUniform4ui(location, v0, v1, v2, v3);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
+      const GLfloat *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniformMatrix4fv.\n");
+#endif
+   glUniformMatrix4fv(location, count, transpose, value);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglDetachShader(GLuint program, GLuint shader)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDetachShader.\n");
+#endif
+   glDetachShader(program, shader);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglGetShaderiv(GLuint shader, GLenum pname, GLint *params)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetShaderiv.\n");
+#endif
+   glGetShaderiv(shader, pname, params);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglAttachShader(GLuint program, GLuint shader)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glAttachShader.\n");
+#endif
+   glAttachShader(program, shader);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+GLint rglGetAttribLocation(GLuint program, const GLchar *name)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetAttribLocation.\n");
+#endif
+   return glGetAttribLocation(program, name);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglShaderSource(GLuint shader, GLsizei count,
+      const GLchar **string, const GLint *length)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glShaderSource.\n");
+#endif
+   return glShaderSource(shader, count, string, length);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglCompileShader(GLuint shader)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glCompileShader.\n");
+#endif
+   glCompileShader(shader);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+GLuint rglCreateProgram(void)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glCreateProgram.\n");
+#endif
+   return glCreateProgram();
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.1
+ */
+void rglGenTextures(GLsizei n, GLuint *textures)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGenTextures.\n");
+#endif
+   glGenTextures(n, textures);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglGetShaderInfoLog(GLuint shader, GLsizei maxLength,
+      GLsizei *length, GLchar *infoLog)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetShaderInfoLog.\n");
+#endif
+   glGetShaderInfoLog(shader, maxLength, length, infoLog);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglGetProgramInfoLog(GLuint shader, GLsizei maxLength,
+      GLsizei *length, GLchar *infoLog)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetProgramInfoLog.\n");
+#endif
+   glGetProgramInfoLog(shader, maxLength, length, infoLog);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+GLboolean rglIsProgram(GLuint program)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glIsProgram.\n");
+#endif
+   return glIsProgram(program);
+}
+
+void rglTexCoord2f(GLfloat s, GLfloat t)
+{
+#ifdef HAVE_LEGACY_GL
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTexCoord2f.\n");
+#endif
+   glTexCoord2f(s, t);
+#endif
+}
+
+/*
+ * Category: Generic vertex attributes
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ *
+ */
+void rglDisableVertexAttribArray(GLuint index)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDisableVertexAttribArray.\n");
+#endif
+   gl_state.vertex_attrib_pointer.enabled[index] = 0;
+   glDisableVertexAttribArray(index);
+}
+
+/*
+ * Category: Generic vertex attributes
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglEnableVertexAttribArray(GLuint index)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glEnableVertexAttribArray.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   gl_state.vertex_attrib_pointer.enabled[index] = 1;
+   glEnableVertexAttribArray(index);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglVertexAttribIPointer(
+      GLuint index,
+      GLint size,
+      GLenum type,
+      GLsizei stride,
+      const GLvoid * pointer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glVertexAttribIPointer.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glVertexAttribIPointer(index, size, type, stride, pointer);
+#endif
+}
+
+void rglVertexAttribLPointer(
+      GLuint index,
+      GLint size,
+      GLenum type,
+      GLsizei stride,
+      const GLvoid * pointer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glVertexAttribLPointer.\n");
+#endif
+#if defined(HAVE_OPENGL)
+   glVertexAttribLPointer(index, size, type, stride, pointer);
+#endif
+}
+
+/*
+ * Category: Generic vertex attributes
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglVertexAttribPointer(GLuint name, GLint size,
+      GLenum type, GLboolean normalized, GLsizei stride,
+      const GLvoid* pointer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glVertexAttribPointer.\n");
+#endif
+   gl_state.attrib_pointer.used[name] = 1;
+   gl_state.attrib_pointer.size[name] = size;
+   gl_state.attrib_pointer.type[name] = type;
+   gl_state.attrib_pointer.normalized[name] = normalized;
+   gl_state.attrib_pointer.stride[name] = stride;
+   gl_state.attrib_pointer.pointer[name] = pointer;
+   gl_state.attrib_pointer.buffer[name] = gl_state.array_buffer;
+   glVertexAttribPointer(name, size, type, normalized, stride, pointer);
+}
+
+/*
+ * Category: Generic vertex attributes
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglBindAttribLocation(GLuint program, GLuint index, const GLchar *name)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindAttribLocation.\n");
+#endif
+   glBindAttribLocation(program, index, name);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglVertexAttrib4f(GLuint name, GLfloat x, GLfloat y,
+      GLfloat z, GLfloat w)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glVertexAttrib4f.\n");
+#endif
+   glVertexAttrib4f(name, x, y, z, w);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglVertexAttrib4fv(GLuint name, GLfloat* v)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glVertexAttrib4fv.\n");
+#endif
+   glVertexAttrib4fv(name, v);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+GLuint rglCreateShader(GLenum shaderType)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glCreateShader.\n");
+#endif
+   return glCreateShader(shaderType);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglDeleteProgram(GLuint program)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteProgram.\n");
+#endif
+   glDeleteProgram(program);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglDeleteShader(GLuint shader)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteShader.\n");
+#endif
+   glDeleteShader(shader);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+GLint rglGetUniformLocation(GLuint program, const GLchar *name)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetUniformLocation.\n");
+#endif
+   return glGetUniformLocation(program, name);
+}
+
+/*
+ * Category: VBO and PBO
+ *
+ * Core in:
+ * OpenGL    : 1.5
+ */
+void rglDeleteBuffers(GLsizei n, const GLuint *buffers)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteBuffers.\n");
+#endif
+   glDeleteBuffers(n, buffers);
+}
+
+/*
+ * Category: VBO and PBO
+ *
+ * Core in:
+ * OpenGL    : 1.5
+ */
+void rglGenBuffers(GLsizei n, GLuint *buffers)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGenBuffers.\n");
+#endif
+   glGenBuffers(n, buffers);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform1f(GLint location, GLfloat v0)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform1f.\n");
+#endif
+   glUniform1f(location, v0);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform1fv(GLint location,  GLsizei count,  const GLfloat *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform1fv.\n");
+#endif
+   glUniform1fv(location, count, value);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform1iv(GLint location,  GLsizei count,  const GLint *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform1iv.\n");
+#endif
+   glUniform1iv(location, count, value);
+}
+
+void rglClearBufferfv(         GLenum buffer,
+       GLint drawBuffer,
+       const GLfloat * value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glClearBufferfv.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
+   glClearBufferfv(buffer, drawBuffer, value);
+#endif
+}
+
+void rglTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTexBuffer.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
+   glTexBuffer(target, internalFormat, buffer);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+const GLubyte* rglGetStringi(GLenum name, GLuint index)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetString.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
+   return glGetStringi(name, index);
+#else
+   return NULL;
+#endif
+}
+
+void rglClearBufferfi(         GLenum buffer,
+       GLint drawBuffer,
+       GLfloat depth,
+       GLint stencil)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glClearBufferfi.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
+   glClearBufferfi(buffer, drawBuffer, depth, stencil);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 3.0
+ */
+void rglRenderbufferStorageMultisample(        GLenum target,
+       GLsizei samples,
+       GLenum internalformat,
+       GLsizei width,
+       GLsizei height)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glRenderbufferStorageMultisample.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3)
+   glRenderbufferStorageMultisample(target, samples, internalformat, width, height);
+#endif
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform1i(GLint location, GLint v0)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform1i.\n");
+#endif
+   glUniform1i(location, v0);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform2f(GLint location, GLfloat v0, GLfloat v1)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform2f.\n");
+#endif
+   glUniform2f(location, v0, v1);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform2i(GLint location, GLint v0, GLint v1)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform2i.\n");
+#endif
+   glUniform2i(location, v0, v1);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform2fv(GLint location, GLsizei count, const GLfloat *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform2fv.\n");
+#endif
+   glUniform2fv(location, count, value);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform3f.\n");
+#endif
+   glUniform3f(location, v0, v1, v2);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform3fv(GLint location, GLsizei count, const GLfloat *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform3fv.\n");
+#endif
+   glUniform3fv(location, count, value);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform4i.\n");
+#endif
+   glUniform4i(location, v0, v1, v2, v3);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform4f.\n");
+#endif
+   glUniform4f(location, v0, v1, v2, v3);
+}
+
+/*
+ * Category: Shaders
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglUniform4fv(GLint location, GLsizei count, const GLfloat *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform4fv.\n");
+#endif
+   glUniform4fv(location, count, value);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.0
+ */
+void rglPolygonOffset(GLfloat factor, GLfloat units)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glPolygonOffset.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glPolygonOffset(factor, units);
+   gl_state.polygonoffset.used   = true;
+   gl_state.polygonoffset.factor = factor;
+   gl_state.polygonoffset.units  = units;
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ */
+void rglGenFramebuffers(GLsizei n, GLuint *ids)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGenFramebuffers.\n");
+#endif
+   glGenFramebuffers(n, ids);
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ */
+void rglBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindFramebuffer.\n");
+#endif
+   glsm_ctl(GLSM_CTL_IMM_VBO_DRAW, NULL);
+   glBindFramebuffer(target, framebuffer);
+   gl_state.framebuf = framebuffer;
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+void rglDrawBuffers(GLsizei n, const GLenum *bufs)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDrawBuffers.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glDrawBuffers(n, bufs);
+#endif
+}
+
+/*
+ * Category: FBO
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.0
+ */
+void *rglMapBufferRange(       GLenum target,
+       GLintptr offset,
+       GLsizeiptr length,
+       GLbitfield access)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glMapBufferRange.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   return glMapBufferRange(target, offset, length, access);
+#else
+   printf("WARNING! Not implemented.\n");
+   return NULL;
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 4.3
+ * OpenGLES  : 3.1
+ */
+void rglTexStorage2DMultisample(GLenum target, GLsizei samples,
+      GLenum internalformat, GLsizei width, GLsizei height,
+      GLboolean fixedsamplelocations)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTexStorage2DMultisample.\n");
+#endif
+#if defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_1)
+   glTexStorage2DMultisample(target, samples, internalformat,
+         width, height, fixedsamplelocations);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGLES  : 3.0
+ */
+void rglTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
+      GLsizei width, GLsizei height)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTexStorage2D.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glTexStorage2D(target, levels, internalFormat, width, height);
+#endif
+}
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : 3.2
+ */
+void rglDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex)
+{
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
+   glDrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 4.2
+ * OpenGLES  : 3.1
+ */
+void rglMemoryBarrier(         GLbitfield barriers)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glMemoryBarrier.\n");
+#endif
+#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3) && defined(HAVE_OPENGLES_3_1)
+   glMemoryBarrier(barriers);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 4.2
+ * OpenGLES  : 3.1
+ */
+void rglBindImageTexture(      GLuint unit,
+       GLuint texture,
+       GLint level,
+       GLboolean layered,
+       GLint layer,
+       GLenum access,
+       GLenum format)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindImageTexture.\n");
+#endif
+#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES3) && defined(HAVE_OPENGLES_3_1)
+   glBindImageTexture(unit, texture, level, layered, layer, access, format);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 4.1
+ * OpenGLES  : 3.1
+ */
+void rglGetProgramBinary(      GLuint program,
+       GLsizei bufsize,
+       GLsizei *length,
+       GLenum *binaryFormat,
+       void *binary)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGetProgramBinary.\n");
+#endif
+#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGetProgramBinary(program, bufsize, length, binaryFormat, binary);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 4.1
+ * OpenGLES  : 3.1
+ */
+void rglProgramBinary(GLuint program,
+       GLenum binaryFormat,
+       const void *binary,
+       GLsizei length)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glProgramBinary.\n");
+#endif
+#if !defined(HAVE_OPENGLES) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_1)
+   glProgramBinary(program, binaryFormat, binary, length);
+#else
+   printf("WARNING! Not implemented.\n");
+#endif
+}
+
+void rglTexImage2DMultisample(         GLenum target,
+       GLsizei samples,
+       GLenum internalformat,
+       GLsizei width,
+       GLsizei height,
+       GLboolean fixedsamplelocations)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTexImage2DMultisample.\n");
+#endif
+#ifndef HAVE_OPENGLES
+   glTexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations);
+#endif
+}
+
+void rglTexImage3D(    GLenum target,
+       GLint level,
+       GLint internalFormat,
+       GLsizei width,
+       GLsizei height,
+       GLsizei depth,
+       GLint border,
+       GLenum format,
+       GLenum type,
+       const GLvoid * data)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTexImage3D.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, data);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.5
+ */
+void * rglMapBuffer(   GLenum target, GLenum access)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glMapBuffer.\n");
+#endif
+#if defined(HAVE_OPENGLES)
+   return glMapBufferOES(target, access);
+#else
+   return glMapBuffer(target, access);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 1.5
+ */
+GLboolean rglUnmapBuffer(      GLenum target)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUnmapBuffer.\n");
+#endif
+#if defined(HAVE_OPENGLES)
+   return glUnmapBufferOES(target);
+#else
+   return glUnmapBuffer(target);
+#endif
+}
+
+void rglBlendEquation(GLenum mode)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBlendEquation.\n");
+#endif
+   glBlendEquation(mode);
+}
+
+void rglBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBlendColor.\n");
+#endif
+   glBlendColor(red, green, blue, alpha);
+}
+
+/*
+ * Category: Blending
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ */
+void rglBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBlendEquationSeparate.\n");
+#endif
+   glBlendEquationSeparate(modeRGB, modeAlpha);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 3.2
+ */
+void rglCopyImageSubData(      GLuint srcName,
+       GLenum srcTarget,
+       GLint srcLevel,
+       GLint srcX,
+       GLint srcY,
+       GLint srcZ,
+       GLuint dstName,
+       GLenum dstTarget,
+       GLint dstLevel,
+       GLint dstX,
+       GLint dstY,
+       GLint dstZ,
+       GLsizei srcWidth,
+       GLsizei srcHeight,
+       GLsizei srcDepth)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glCopyImageSubData.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES_3_2)
+   glCopyImageSubData(srcName,
+         srcTarget,
+         srcLevel,
+         srcX,
+         srcY,
+         srcZ,
+         dstName,
+         dstTarget,
+         dstLevel,
+         dstX,
+         dstY,
+         dstZ,
+         srcWidth,
+         srcHeight,
+         srcDepth);
+#endif
+}
+
+/*
+ * Category: VAO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 3.0
+ */
+void rglBindVertexArray(GLuint array)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBindVertexArray.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glBindVertexArray(array);
+#endif
+}
+
+/*
+ * Category: VAO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 3.0
+ */
+void rglGenVertexArrays(GLsizei n, GLuint *arrays)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glGenVertexArrays.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glGenVertexArrays(n, arrays);
+#endif
+}
+
+/*
+ * Category: VAO
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 3.0
+ */
+void rglDeleteVertexArrays(GLsizei n, const GLuint *arrays)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteVertexArrays.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glDeleteVertexArrays(n, arrays);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : 3.0
+ */
+void *rglFenceSync(GLenum condition, GLbitfield flags)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glFenceSync.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   return (GLsync)glFenceSync(condition, flags);
+#else
+   return NULL;
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : 3.0
+ */
+void rglDeleteSync(void * sync)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDeleteSync.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+  glDeleteSync((GLsync)sync);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : 3.0
+ */
+void rglWaitSync(void *sync, GLbitfield flags, uint64_t timeout)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glWaitSync.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glWaitSync((GLsync)sync, flags, (GLuint64)timeout);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 4.4
+ * OpenGLES  : Not available
+ */
+void rglBufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GLbitfield flags)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glBufferStorage.\n");
+#endif
+#if defined(HAVE_OPENGL)
+   glBufferStorage(target, size, data, flags);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 2.0
+ * OpenGLES  : 2.0
+ */
+
+void rglUniform2iv(    GLint location,
+       GLsizei count,
+       const GLint *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform2iv.\n");
+#endif
+   glUniform2iv(location, count, value);
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : ?.?
+ */
+
+void rglUniform2uiv(   GLint location,
+       GLsizei count,
+       const GLuint *value)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glUniform2uiv.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+   glUniform2uiv(location, count, value);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 4.3
+ * OpenGLES  : ?.?
+ */
+void rglTextureView(   GLuint texture,
+       GLenum target,
+       GLuint origtexture,
+       GLenum internalformat,
+       GLuint minlevel,
+       GLuint numlevels,
+       GLuint minlayer,
+       GLuint numlayers)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glTextureView.\n");
+#endif
+#if defined(HAVE_OPENGL)
+   glTextureView(texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers);
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.0
+ * OpenGLES  : 3.0
+ */
+void rglFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glFlushMappedBufferRange.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+  glFlushMappedBufferRange(target, offset, length);
+#endif
+}
+
+#ifndef GL_WAIT_FAILED
+#define GL_WAIT_FAILED                                   0x911D
+#endif
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : 3.0
+ */
+GLenum rglClientWaitSync(void *sync, GLbitfield flags, uint64_t timeout)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glClientWaitSync.\n");
+#endif
+#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) && defined(HAVE_OPENGLES3)
+  return glClientWaitSync((GLsync)sync, flags, (GLuint64)timeout);
+#else
+  return GL_WAIT_FAILED;
+#endif
+}
+
+/*
+ *
+ * Core in:
+ * OpenGL    : 3.2
+ * OpenGLES  : Not available
+ */
+void rglDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+                              GLvoid *indices, GLint basevertex)
+{
+#ifdef GLSM_DEBUG
+   log_cb(RETRO_LOG_INFO, "glDrawElementsBaseVertex.\n");
+#endif
+#if defined(HAVE_OPENGL)
+   glDrawElementsBaseVertex(mode, count, type, indices, basevertex);
+#endif
+}
+
+/* GLSM-side */
+
+static void glsm_state_setup(void)
+{
+   unsigned i;
+
+   gl_state.cap_translate[SGL_DEPTH_TEST]           = GL_DEPTH_TEST;
+   gl_state.cap_translate[SGL_BLEND]                = GL_BLEND;
+   gl_state.cap_translate[SGL_POLYGON_OFFSET_FILL]  = GL_POLYGON_OFFSET_FILL;
+   gl_state.cap_translate[SGL_FOG]                  = GL_FOG;
+   gl_state.cap_translate[SGL_CULL_FACE]            = GL_CULL_FACE;
+   gl_state.cap_translate[SGL_ALPHA_TEST]           = GL_ALPHA_TEST;
+   gl_state.cap_translate[SGL_SCISSOR_TEST]         = GL_SCISSOR_TEST;
+   gl_state.cap_translate[SGL_STENCIL_TEST]         = GL_STENCIL_TEST;
+
+#ifndef HAVE_OPENGLES
+   gl_state.cap_translate[SGL_COLOR_LOGIC_OP]       = GL_COLOR_LOGIC_OP;
+   gl_state.cap_translate[SGL_CLIP_DISTANCE0]       = GL_CLIP_DISTANCE0;
+   gl_state.cap_translate[SGL_DEPTH_CLAMP]          = GL_DEPTH_CLAMP;
+#endif
+
+   for (i = 0; i < MAX_ATTRIB; i++)
+   {
+      gl_state.vertex_attrib_pointer.enabled[i] = 0;
+      gl_state.attrib_pointer.used[i] = 0;
+   }
+
+   glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &glsm_max_textures);
+
+   gl_state.bind_textures.ids           = (GLuint*)calloc(glsm_max_textures, sizeof(GLuint));
+
+   default_framebuffer                  = glsm_get_current_framebuffer();
+   gl_state.framebuf                    = default_framebuffer;
+   gl_state.cullface.mode               = GL_BACK;
+   gl_state.frontface.mode              = GL_CCW;
+
+   gl_state.blendfunc_separate.used     = false;
+   gl_state.blendfunc_separate.srcRGB   = GL_ONE;
+   gl_state.blendfunc_separate.dstRGB   = GL_ZERO;
+   gl_state.blendfunc_separate.srcAlpha = GL_ONE;
+   gl_state.blendfunc_separate.dstAlpha = GL_ZERO;
+
+   gl_state.depthfunc.used              = false;
+
+   gl_state.colormask.used              = false;
+   gl_state.colormask.red               = GL_TRUE;
+   gl_state.colormask.green             = GL_TRUE;
+   gl_state.colormask.blue              = GL_TRUE;
+   gl_state.colormask.alpha             = GL_TRUE;
+
+   gl_state.polygonoffset.used          = false;
+
+   gl_state.depthfunc.func              = GL_LESS;
+
+#ifndef HAVE_OPENGLES
+   gl_state.colorlogicop                = GL_COPY;
+#endif
+
+#ifdef CORE
+   glGenVertexArrays(1, &gl_state.vao);
+#endif
+}
+
+static void glsm_state_bind(void)
+{
+   unsigned i;
+#ifdef CORE
+   glBindVertexArray(gl_state.vao);
+#endif
+   glBindBuffer(GL_ARRAY_BUFFER, gl_state.array_buffer);
+
+   for (i = 0; i < MAX_ATTRIB; i++)
+   {
+      if (gl_state.vertex_attrib_pointer.enabled[i])
+         glEnableVertexAttribArray(i);
+      else
+         glDisableVertexAttribArray(i);
+
+      if (gl_state.attrib_pointer.used[i] && gl_state.attrib_pointer.buffer[i] == gl_state.array_buffer)
+      {
+         glVertexAttribPointer(
+               i,
+               gl_state.attrib_pointer.size[i],
+               gl_state.attrib_pointer.type[i],
+               gl_state.attrib_pointer.normalized[i],
+               gl_state.attrib_pointer.stride[i],
+               gl_state.attrib_pointer.pointer[i]);
+      }
+   }
+
+   glBindFramebuffer(RARCH_GL_FRAMEBUFFER, default_framebuffer);
+
+   if (gl_state.blendfunc.used)
+      glBlendFunc(
+            gl_state.blendfunc.sfactor,
+            gl_state.blendfunc.dfactor);
+
+   if (gl_state.blendfunc_separate.used)
+      glBlendFuncSeparate(
+            gl_state.blendfunc_separate.srcRGB,
+            gl_state.blendfunc_separate.dstRGB,
+            gl_state.blendfunc_separate.srcAlpha,
+            gl_state.blendfunc_separate.dstAlpha
+            );
+
+   glClearColor(
+         gl_state.clear_color.r,
+         gl_state.clear_color.g,
+         gl_state.clear_color.b,
+         gl_state.clear_color.a);
+
+   if (gl_state.depthfunc.used)
+      glDepthFunc(gl_state.depthfunc.func);
+
+   if (gl_state.colormask.used)
+      glColorMask(
+            gl_state.colormask.red,
+            gl_state.colormask.green,
+            gl_state.colormask.blue,
+            gl_state.colormask.alpha);
+
+   if (gl_state.cullface.used)
+      glCullFace(gl_state.cullface.mode);
+
+   if (gl_state.depthmask.used)
+      glDepthMask(gl_state.depthmask.mask);
+
+   if (gl_state.polygonoffset.used)
+      glPolygonOffset(
+            gl_state.polygonoffset.factor,
+            gl_state.polygonoffset.units);
+
+   if (gl_state.scissor.used)
+      glScissor(
+            gl_state.scissor.x,
+            gl_state.scissor.y,
+            gl_state.scissor.w,
+            gl_state.scissor.h);
+
+   glUseProgram(gl_state.program);
+
+   glViewport(
+         gl_state.viewport.x,
+         gl_state.viewport.y,
+         gl_state.viewport.w,
+         gl_state.viewport.h);
+
+   for(i = 0; i < SGL_CAP_MAX; i ++)
+   {
+      if (gl_state.cap_state[i])
+         glEnable(gl_state.cap_translate[i]);
+   }
+
+   if (gl_state.frontface.used)
+      glFrontFace(gl_state.frontface.mode);
+
+   if (gl_state.stencilmask.used)
+      glStencilMask(gl_state.stencilmask.mask);
+
+   if (gl_state.stencilop.used)
+      glStencilOp(gl_state.stencilop.sfail,
+            gl_state.stencilop.dpfail,
+            gl_state.stencilop.dppass);
+
+   if (gl_state.stencilfunc.used)
+      glStencilFunc(
+            gl_state.stencilfunc.func,
+            gl_state.stencilfunc.ref,
+            gl_state.stencilfunc.mask);
+
+   for (i = 0; i < glsm_max_textures; i ++)
+   {
+      glActiveTexture(GL_TEXTURE0 + i);
+      glBindTexture(GL_TEXTURE_2D, gl_state.bind_textures.ids[i]);
+   }
+
+   glActiveTexture(GL_TEXTURE0 + gl_state.active_texture);
+}
+
+static void glsm_state_unbind(void)
+{
+   unsigned i;
+#ifdef CORE
+   glBindVertexArray(0);
+#endif
+   for (i = 0; i < SGL_CAP_MAX; i ++)
+   {
+      if (gl_state.cap_state[i])
+         glDisable(gl_state.cap_translate[i]);
+   }
+
+   glBlendFunc(GL_ONE, GL_ZERO);
+
+   if (gl_state.colormask.used)
+      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+   if (gl_state.blendfunc_separate.used)
+      glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
+
+   if (gl_state.cullface.used)
+      glCullFace(GL_BACK);
+
+   if (gl_state.depthmask.used)
+      glDepthMask(GL_TRUE);
+
+   if (gl_state.polygonoffset.used)
+      glPolygonOffset(0, 0);
+
+   glUseProgram(0);
+   glClearColor(0,0,0,0.0f);
+
+   if (gl_state.depthrange.used)
+      rglDepthRange(0, 1);
+
+   glStencilMask(1);
+   glFrontFace(GL_CCW);
+   if (gl_state.depthfunc.used)
+      glDepthFunc(GL_LESS);
+
+   if (gl_state.stencilop.used)
+      glStencilOp(GL_KEEP,GL_KEEP, GL_KEEP);
+
+   if (gl_state.stencilfunc.used)
+      glStencilFunc(GL_ALWAYS,0,1);
+
+   /* Clear textures */
+   for (i = 0; i < glsm_max_textures; i ++)
+   {
+      glActiveTexture(GL_TEXTURE0 + i);
+      glBindTexture(GL_TEXTURE_2D, 0);
+   }
+   glActiveTexture(GL_TEXTURE0);
+
+   for (i = 0; i < MAX_ATTRIB; i ++)
+      glDisableVertexAttribArray(i);
+
+   glBindFramebuffer(RARCH_GL_FRAMEBUFFER, 0);
+}
+
+static bool glsm_state_ctx_destroy(void *data)
+{
+   if (gl_state.bind_textures.ids)
+      free(gl_state.bind_textures.ids);
+   gl_state.bind_textures.ids = NULL;
+
+   return true;
+}
+
+static bool glsm_state_ctx_init(glsm_ctx_params_t *params)
+{
+   if (!params || !params->environ_cb)
+      return false;
+
+#ifdef HAVE_OPENGLES
+#if defined(HAVE_OPENGLES_3_1)
+   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES_VERSION;
+   hw_render.version_major      = 3;
+   hw_render.version_minor      = 1;
+#elif defined(HAVE_OPENGLES3)
+   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES3;
+#else
+   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGLES2;
+#endif
+#else
+   hw_render.context_type       = RETRO_HW_CONTEXT_OPENGL;
+   if (params->context_type != RETRO_HW_CONTEXT_NONE)
+      hw_render.context_type    = params->context_type;
+   if (params->major != 0)
+      hw_render.version_major   = params->major;
+   if (params->minor != 0)
+      hw_render.version_minor   = params->minor;
+#endif
+
+   hw_render.context_reset      = params->context_reset;
+   hw_render.context_destroy    = params->context_destroy;
+   hw_render.stencil            = params->stencil;
+   hw_render.depth              = true;
+   hw_render.bottom_left_origin = true;
+   hw_render.cache_context      = false;
+
+   if (!params->environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render))
+      return false;
+
+   return true;
+}
+
+GLuint glsm_get_current_framebuffer(void)
+{
+   return hw_render.get_current_framebuffer();
+}
+
+bool glsm_ctl(enum glsm_state_ctl state, void *data)
+{
+   switch (state)
+   {
+      case GLSM_CTL_IMM_VBO_DRAW:
+         return false;
+      case GLSM_CTL_IMM_VBO_DISABLE:
+         return false;
+      case GLSM_CTL_IS_IMM_VBO:
+         return false;
+      case GLSM_CTL_SET_IMM_VBO:
+         break;
+      case GLSM_CTL_UNSET_IMM_VBO:
+         break;
+      case GLSM_CTL_PROC_ADDRESS_GET:
+         {
+            glsm_ctx_proc_address_t *proc = (glsm_ctx_proc_address_t*)data;
+            if (!hw_render.get_proc_address)
+               return false;
+            proc->addr = hw_render.get_proc_address;
+         }
+         break;
+      case GLSM_CTL_STATE_CONTEXT_RESET:
+         rglgen_resolve_symbols(hw_render.get_proc_address);
+         break;
+      case GLSM_CTL_STATE_CONTEXT_DESTROY:
+         glsm_state_ctx_destroy(data);
+         break;
+      case GLSM_CTL_STATE_CONTEXT_INIT:
+         return glsm_state_ctx_init((glsm_ctx_params_t*)data);
+      case GLSM_CTL_STATE_SETUP:
+         glsm_state_setup();
+         break;
+      case GLSM_CTL_STATE_UNBIND:
+         glsm_state_unbind();
+         break;
+      case GLSM_CTL_STATE_BIND:
+         glsm_state_bind();
+         break;
+      case GLSM_CTL_NONE:
+      default:
+         break;
+   }
+
+   return true;
+}
diff --git a/deps/libretro-common/glsym/README.md b/deps/libretro-common/glsym/README.md
new file mode 100644 (file)
index 0000000..5130194
--- /dev/null
@@ -0,0 +1,11 @@
+# Autogenerate GL extension loaders
+
+## OpenGL desktop
+
+Use Khronos' recent [header](www.opengl.org/registry/api/glext.h).
+
+    ./glgen.py /usr/include/GL/glext.h glsym_gl.h glsym_gl.c
+
+## OpenGL ES
+
+    ./glgen.py /usr/include/GLES2/gl2ext.h glsym_es2.h glsym_es2.c
diff --git a/deps/libretro-common/glsym/glgen.py b/deps/libretro-common/glsym/glgen.py
new file mode 100755 (executable)
index 0000000..8d82357
--- /dev/null
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+
+"""
+   License statement applies to this file (glgen.py) only.
+
+   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.
+"""
+
+import sys
+import os
+import re
+
+banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]
+
+def noext(sym):
+   for ext in banned_ext:
+      if sym.endswith(ext):
+         return False
+   return True
+
+def fix_multiline_functions(lines):
+   fixed_lines = []
+   temp_lines = []
+   for line in lines:
+      if line.count('(') > line.count(')'):
+         temp_lines.append(line)
+      else:
+         if len(temp_lines) > 0:
+            if line.count(')') > line.count('('):
+               temp_lines.append(line)
+               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
+               fixed_lines.append(fixed_line)
+               temp_lines = []
+            else:
+               temp_lines.append(line)
+         else:
+            fixed_lines.append(line)
+   return fixed_lines
+
+def find_gl_symbols(lines):
+   typedefs = []
+   syms = []
+   for line in lines:
+      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
+      g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
+      if m and noext(m.group(1)):
+         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
+      if g and noext(g.group(1)):
+         syms.append(g.group(1))
+   return (typedefs, syms)
+
+def generate_defines(gl_syms):
+   res = []
+   for line in gl_syms:
+      res.append('#define {} __rglgen_{}'.format(line, line))
+   return res
+
+def generate_declarations(gl_syms):
+   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]
+
+def generate_macros(gl_syms):
+   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]
+
+def dump(f, lines):
+   f.write('\n'.join(lines))
+   f.write('\n\n')
+
+if __name__ == '__main__':
+
+   if len(sys.argv) > 4:
+      for banned in sys.argv[4:]:
+         banned_ext.append(banned)
+
+   with open(sys.argv[1], 'r') as f:
+      lines = fix_multiline_functions(f.readlines())
+      typedefs, syms = find_gl_symbols(lines)
+
+      overrides = generate_defines(syms)
+      declarations = generate_declarations(syms)
+      externs = ['extern ' + x for x in declarations]
+
+      macros = generate_macros(syms)
+
+   with open(sys.argv[2], 'w') as f:
+      f.write('#ifndef RGLGEN_DECL_H__\n')
+      f.write('#define RGLGEN_DECL_H__\n')
+
+      f.write('#ifdef __cplusplus\n')
+      f.write('extern "C" {\n')
+      f.write('#endif\n')
+
+      f.write('#ifdef GL_APIENTRY\n')
+      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('#else\n')
+      f.write('#ifndef APIENTRY\n')
+      f.write('#define APIENTRY\n')
+      f.write('#endif\n')
+      f.write('#ifndef APIENTRYP\n')
+      f.write('#define APIENTRYP APIENTRY *\n')
+      f.write('#endif\n')
+      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('#endif\n')
+
+      f.write('#ifndef GL_OES_EGL_image\n')
+      f.write('typedef void *GLeglImageOES;\n')
+      f.write('#endif\n')
+
+      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
+      f.write('typedef GLint GLfixed;\n')
+      f.write('#endif\n')
+
+      f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\n')
+      f.write('typedef long long int GLint64;\n')
+      f.write('typedef unsigned long long int GLuint64;\n')
+      f.write('typedef unsigned long long int GLuint64EXT;\n')
+      f.write('typedef struct __GLsync *GLsync;\n')
+      f.write('#endif\n')
+
+      dump(f, typedefs)
+      dump(f, overrides)
+      dump(f, externs)
+
+      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
+      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')
+
+      f.write('#ifdef __cplusplus\n')
+      f.write('}\n')
+      f.write('#endif\n')
+
+      f.write('#endif\n')
+
+   with open(sys.argv[3], 'w') as f:
+      f.write('#include "glsym/glsym.h"\n')
+      f.write('#include <stddef.h>\n')
+      f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
+      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
+      dump(f, macros)
+      f.write('    { NULL, NULL },\n')
+      f.write('};\n')
+      dump(f, declarations)
diff --git a/deps/libretro-common/glsym/glsym_es2.c b/deps/libretro-common/glsym/glsym_es2.c
new file mode 100644 (file)
index 0000000..b9c0706
--- /dev/null
@@ -0,0 +1,409 @@
+#include "glsym/glsym.h"
+#include <stddef.h>
+#define SYM(x) { "gl" #x, &(gl##x) }
+const struct rglgen_sym_map rglgen_symbol_map[] = {
+    SYM(BlendBarrierKHR),
+    SYM(DebugMessageControlKHR),
+    SYM(DebugMessageInsertKHR),
+    SYM(DebugMessageCallbackKHR),
+    SYM(GetDebugMessageLogKHR),
+    SYM(PushDebugGroupKHR),
+    SYM(PopDebugGroupKHR),
+    SYM(ObjectLabelKHR),
+    SYM(GetObjectLabelKHR),
+    SYM(ObjectPtrLabelKHR),
+    SYM(GetObjectPtrLabelKHR),
+    SYM(GetPointervKHR),
+    SYM(GetGraphicsResetStatusKHR),
+    SYM(ReadnPixelsKHR),
+    SYM(GetnUniformfvKHR),
+    SYM(GetnUniformivKHR),
+    SYM(GetnUniformuivKHR),
+    SYM(EGLImageTargetTexture2DOES),
+    SYM(EGLImageTargetRenderbufferStorageOES),
+    SYM(CopyImageSubDataOES),
+    SYM(EnableiOES),
+    SYM(DisableiOES),
+    SYM(BlendEquationiOES),
+    SYM(BlendEquationSeparateiOES),
+    SYM(BlendFunciOES),
+    SYM(BlendFuncSeparateiOES),
+    SYM(ColorMaskiOES),
+    SYM(IsEnablediOES),
+    SYM(DrawElementsBaseVertexOES),
+    SYM(DrawRangeElementsBaseVertexOES),
+    SYM(DrawElementsInstancedBaseVertexOES),
+    SYM(MultiDrawElementsBaseVertexOES),
+    SYM(FramebufferTextureOES),
+    SYM(GetProgramBinaryOES),
+    SYM(ProgramBinaryOES),
+    SYM(MapBufferOES),
+    SYM(UnmapBufferOES),
+    SYM(GetBufferPointervOES),
+    SYM(PrimitiveBoundingBoxOES),
+    SYM(MinSampleShadingOES),
+    SYM(PatchParameteriOES),
+    SYM(TexImage3DOES),
+    SYM(TexSubImage3DOES),
+    SYM(CopyTexSubImage3DOES),
+    SYM(CompressedTexImage3DOES),
+    SYM(CompressedTexSubImage3DOES),
+    SYM(FramebufferTexture3DOES),
+    SYM(TexParameterIivOES),
+    SYM(TexParameterIuivOES),
+    SYM(GetTexParameterIivOES),
+    SYM(GetTexParameterIuivOES),
+    SYM(SamplerParameterIivOES),
+    SYM(SamplerParameterIuivOES),
+    SYM(GetSamplerParameterIivOES),
+    SYM(GetSamplerParameterIuivOES),
+    SYM(TexBufferOES),
+    SYM(TexBufferRangeOES),
+    SYM(TexStorage3DMultisampleOES),
+    SYM(TextureViewOES),
+    SYM(BindVertexArrayOES),
+    SYM(DeleteVertexArraysOES),
+    SYM(GenVertexArraysOES),
+    SYM(IsVertexArrayOES),
+    SYM(ViewportArrayvOES),
+    SYM(ViewportIndexedfOES),
+    SYM(ViewportIndexedfvOES),
+    SYM(ScissorArrayvOES),
+    SYM(ScissorIndexedOES),
+    SYM(ScissorIndexedvOES),
+    SYM(DepthRangeArrayfvOES),
+    SYM(DepthRangeIndexedfOES),
+    SYM(GetFloati_vOES),
+    SYM(DrawArraysInstancedBaseInstanceEXT),
+    SYM(DrawElementsInstancedBaseInstanceEXT),
+    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
+    SYM(BindFragDataLocationIndexedEXT),
+    SYM(BindFragDataLocationEXT),
+    SYM(GetProgramResourceLocationIndexEXT),
+    SYM(GetFragDataIndexEXT),
+    SYM(BufferStorageEXT),
+    SYM(ClearTexImageEXT),
+    SYM(ClearTexSubImageEXT),
+    SYM(CopyImageSubDataEXT),
+    SYM(LabelObjectEXT),
+    SYM(GetObjectLabelEXT),
+    SYM(InsertEventMarkerEXT),
+    SYM(PushGroupMarkerEXT),
+    SYM(PopGroupMarkerEXT),
+    SYM(DiscardFramebufferEXT),
+    SYM(GenQueriesEXT),
+    SYM(DeleteQueriesEXT),
+    SYM(IsQueryEXT),
+    SYM(BeginQueryEXT),
+    SYM(EndQueryEXT),
+    SYM(QueryCounterEXT),
+    SYM(GetQueryivEXT),
+    SYM(GetQueryObjectivEXT),
+    SYM(GetQueryObjectuivEXT),
+    SYM(DrawBuffersEXT),
+    SYM(EnableiEXT),
+    SYM(DisableiEXT),
+    SYM(BlendEquationiEXT),
+    SYM(BlendEquationSeparateiEXT),
+    SYM(BlendFunciEXT),
+    SYM(BlendFuncSeparateiEXT),
+    SYM(ColorMaskiEXT),
+    SYM(IsEnablediEXT),
+    SYM(DrawElementsBaseVertexEXT),
+    SYM(DrawRangeElementsBaseVertexEXT),
+    SYM(DrawElementsInstancedBaseVertexEXT),
+    SYM(MultiDrawElementsBaseVertexEXT),
+    SYM(DrawArraysInstancedEXT),
+    SYM(DrawElementsInstancedEXT),
+    SYM(FramebufferTextureEXT),
+    SYM(VertexAttribDivisorEXT),
+    SYM(MapBufferRangeEXT),
+    SYM(FlushMappedBufferRangeEXT),
+    SYM(MultiDrawArraysEXT),
+    SYM(MultiDrawElementsEXT),
+    SYM(MultiDrawArraysIndirectEXT),
+    SYM(MultiDrawElementsIndirectEXT),
+    SYM(RenderbufferStorageMultisampleEXT),
+    SYM(FramebufferTexture2DMultisampleEXT),
+    SYM(ReadBufferIndexedEXT),
+    SYM(DrawBuffersIndexedEXT),
+    SYM(GetIntegeri_vEXT),
+    SYM(PolygonOffsetClampEXT),
+    SYM(PrimitiveBoundingBoxEXT),
+    SYM(RasterSamplesEXT),
+    SYM(GetGraphicsResetStatusEXT),
+    SYM(ReadnPixelsEXT),
+    SYM(GetnUniformfvEXT),
+    SYM(GetnUniformivEXT),
+    SYM(ActiveShaderProgramEXT),
+    SYM(BindProgramPipelineEXT),
+    SYM(CreateShaderProgramvEXT),
+    SYM(DeleteProgramPipelinesEXT),
+    SYM(GenProgramPipelinesEXT),
+    SYM(GetProgramPipelineInfoLogEXT),
+    SYM(GetProgramPipelineivEXT),
+    SYM(IsProgramPipelineEXT),
+    SYM(ProgramParameteriEXT),
+    SYM(ProgramUniform1fEXT),
+    SYM(ProgramUniform1fvEXT),
+    SYM(ProgramUniform1iEXT),
+    SYM(ProgramUniform1ivEXT),
+    SYM(ProgramUniform2fEXT),
+    SYM(ProgramUniform2fvEXT),
+    SYM(ProgramUniform2iEXT),
+    SYM(ProgramUniform2ivEXT),
+    SYM(ProgramUniform3fEXT),
+    SYM(ProgramUniform3fvEXT),
+    SYM(ProgramUniform3iEXT),
+    SYM(ProgramUniform3ivEXT),
+    SYM(ProgramUniform4fEXT),
+    SYM(ProgramUniform4fvEXT),
+    SYM(ProgramUniform4iEXT),
+    SYM(ProgramUniform4ivEXT),
+    SYM(ProgramUniformMatrix2fvEXT),
+    SYM(ProgramUniformMatrix3fvEXT),
+    SYM(ProgramUniformMatrix4fvEXT),
+    SYM(UseProgramStagesEXT),
+    SYM(ValidateProgramPipelineEXT),
+    SYM(ProgramUniform1uiEXT),
+    SYM(ProgramUniform2uiEXT),
+    SYM(ProgramUniform3uiEXT),
+    SYM(ProgramUniform4uiEXT),
+    SYM(ProgramUniform1uivEXT),
+    SYM(ProgramUniform2uivEXT),
+    SYM(ProgramUniform3uivEXT),
+    SYM(ProgramUniform4uivEXT),
+    SYM(ProgramUniformMatrix2x3fvEXT),
+    SYM(ProgramUniformMatrix3x2fvEXT),
+    SYM(ProgramUniformMatrix2x4fvEXT),
+    SYM(ProgramUniformMatrix4x2fvEXT),
+    SYM(ProgramUniformMatrix3x4fvEXT),
+    SYM(ProgramUniformMatrix4x3fvEXT),
+    SYM(FramebufferPixelLocalStorageSizeEXT),
+    SYM(GetFramebufferPixelLocalStorageSizeEXT),
+    SYM(ClearPixelLocalStorageuiEXT),
+    SYM(TexPageCommitmentEXT),
+    SYM(PatchParameteriEXT),
+    SYM(TexParameterIivEXT),
+    SYM(TexParameterIuivEXT),
+    SYM(GetTexParameterIivEXT),
+    SYM(GetTexParameterIuivEXT),
+    SYM(SamplerParameterIivEXT),
+    SYM(SamplerParameterIuivEXT),
+    SYM(GetSamplerParameterIivEXT),
+    SYM(GetSamplerParameterIuivEXT),
+    SYM(TexBufferEXT),
+    SYM(TexBufferRangeEXT),
+    SYM(TexStorage1DEXT),
+    SYM(TexStorage2DEXT),
+    SYM(TexStorage3DEXT),
+    SYM(TextureStorage1DEXT),
+    SYM(TextureStorage2DEXT),
+    SYM(TextureStorage3DEXT),
+    SYM(TextureViewEXT),
+    SYM(FramebufferTextureMultiviewOVR),
+    SYM(FramebufferTextureMultisampleMultiviewOVR),
+
+    { NULL, NULL },
+};
+RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
+RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
+RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
+RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
+RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
+RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
+RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
+RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
+RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
+RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
+RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
+RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
+RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
+RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
+RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
+RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
+RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
+RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
+RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
+RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
+RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
+RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
+RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
+RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
+RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
+RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
+RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
+RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
+RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
+RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
+RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
+RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
+RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
+RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
+RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
+RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
+RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
+RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
+RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
+RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
+RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
+RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
+RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
+RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
+RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
+RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
+RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
+RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
+RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
+RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
+RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
+RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
+RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
+RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
+RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
+RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
+RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
+RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
+RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
+RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
+RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
+RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
+RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
+RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
+RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
+RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
+RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
+RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
+RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
+RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
+RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
+RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
+RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
+RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
+RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
+RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
+RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
+RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
+RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
+RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
+RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
+RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
+RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
+RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
+RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
+RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
+RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
+RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
+RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
+RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
+RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
+RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
+RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
+RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
+RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
+RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
+RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
+RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
+RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
+RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
+RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
+RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
+RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
+RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
+RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
+RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
+RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
+RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
+RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
+RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
+RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
+RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
+RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
+RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
+RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
+RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
+RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
+RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
+RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
+RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
+RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
+RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
+RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
+RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
+RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
+RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
+RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
+RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
+RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
+RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
+RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
+RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
+RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
+RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
+RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
+RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
+RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
+RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
+RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
+RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
+RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
+RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
+RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
+RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
+RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
+RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
+RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
+RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
+RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
+RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
+RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
+RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
+RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
+RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
+RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
+RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
+RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
+RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
+RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
+RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
+RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
+RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
+RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
+RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
+RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
+RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
+RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
+RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
+RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
+RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
+RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
+RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
+RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
+RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
+RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
+RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
+RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
+RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
+RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
+RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
+RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
+RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
+RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
+RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
+RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
+RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
diff --git a/deps/libretro-common/glsym/glsym_es3.c b/deps/libretro-common/glsym/glsym_es3.c
new file mode 100644 (file)
index 0000000..86d46d9
--- /dev/null
@@ -0,0 +1,413 @@
+#include "glsym/glsym.h"
+#include <stddef.h>
+#define SYM(x) { "gl" #x, &(gl##x) }
+const struct rglgen_sym_map rglgen_symbol_map[] = {
+    SYM(BlendBarrierKHR),
+    SYM(DebugMessageControlKHR),
+    SYM(DebugMessageInsertKHR),
+    SYM(DebugMessageCallbackKHR),
+    SYM(GetDebugMessageLogKHR),
+    SYM(PushDebugGroupKHR),
+    SYM(PopDebugGroupKHR),
+    SYM(ObjectLabelKHR),
+    SYM(GetObjectLabelKHR),
+    SYM(ObjectPtrLabelKHR),
+    SYM(GetObjectPtrLabelKHR),
+    SYM(GetPointervKHR),
+    SYM(GetGraphicsResetStatusKHR),
+    SYM(ReadnPixelsKHR),
+    SYM(GetnUniformfvKHR),
+    SYM(GetnUniformivKHR),
+    SYM(GetnUniformuivKHR),
+    SYM(EGLImageTargetTexture2DOES),
+    SYM(EGLImageTargetRenderbufferStorageOES),
+    SYM(CopyImageSubDataOES),
+    SYM(EnableiOES),
+    SYM(DisableiOES),
+    SYM(BlendEquationiOES),
+    SYM(BlendEquationSeparateiOES),
+    SYM(BlendFunciOES),
+    SYM(BlendFuncSeparateiOES),
+    SYM(ColorMaskiOES),
+    SYM(IsEnablediOES),
+    SYM(DrawElementsBaseVertexOES),
+    SYM(DrawRangeElementsBaseVertexOES),
+    SYM(DrawElementsInstancedBaseVertexOES),
+    SYM(MultiDrawElementsBaseVertexOES),
+    SYM(FramebufferTextureOES),
+    SYM(GetProgramBinaryOES),
+    SYM(ProgramBinaryOES),
+    SYM(MapBufferOES),
+    SYM(UnmapBufferOES),
+    SYM(GetBufferPointervOES),
+    SYM(PrimitiveBoundingBoxOES),
+    SYM(MinSampleShadingOES),
+    SYM(PatchParameteriOES),
+    SYM(TexImage3DOES),
+    SYM(TexSubImage3DOES),
+    SYM(CopyTexSubImage3DOES),
+    SYM(CompressedTexImage3DOES),
+    SYM(CompressedTexSubImage3DOES),
+    SYM(FramebufferTexture3DOES),
+    SYM(TexParameterIivOES),
+    SYM(TexParameterIuivOES),
+    SYM(GetTexParameterIivOES),
+    SYM(GetTexParameterIuivOES),
+    SYM(SamplerParameterIivOES),
+    SYM(SamplerParameterIuivOES),
+    SYM(GetSamplerParameterIivOES),
+    SYM(GetSamplerParameterIuivOES),
+    SYM(TexBufferOES),
+    SYM(TexBufferRangeOES),
+    SYM(TexStorage3DMultisampleOES),
+    SYM(TextureViewOES),
+    SYM(BindVertexArrayOES),
+    SYM(DeleteVertexArraysOES),
+    SYM(GenVertexArraysOES),
+    SYM(IsVertexArrayOES),
+    SYM(ViewportArrayvOES),
+    SYM(ViewportIndexedfOES),
+    SYM(ViewportIndexedfvOES),
+    SYM(ScissorArrayvOES),
+    SYM(ScissorIndexedOES),
+    SYM(ScissorIndexedvOES),
+    SYM(DepthRangeArrayfvOES),
+    SYM(DepthRangeIndexedfOES),
+    SYM(GetFloati_vOES),
+    SYM(DrawArraysInstancedBaseInstanceEXT),
+    SYM(DrawElementsInstancedBaseInstanceEXT),
+    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
+    SYM(BindFragDataLocationIndexedEXT),
+    SYM(BindFragDataLocationEXT),
+    SYM(GetProgramResourceLocationIndexEXT),
+    SYM(GetFragDataIndexEXT),
+    SYM(BufferStorageEXT),
+    SYM(ClearTexImageEXT),
+    SYM(ClearTexSubImageEXT),
+    SYM(CopyImageSubDataEXT),
+    SYM(LabelObjectEXT),
+    SYM(GetObjectLabelEXT),
+    SYM(InsertEventMarkerEXT),
+    SYM(PushGroupMarkerEXT),
+    SYM(PopGroupMarkerEXT),
+    SYM(DiscardFramebufferEXT),
+    SYM(GenQueriesEXT),
+    SYM(DeleteQueriesEXT),
+    SYM(IsQueryEXT),
+    SYM(BeginQueryEXT),
+    SYM(EndQueryEXT),
+    SYM(QueryCounterEXT),
+    SYM(GetQueryivEXT),
+    SYM(GetQueryObjectivEXT),
+    SYM(GetQueryObjectuivEXT),
+    SYM(GetQueryObjecti64vEXT),
+    SYM(GetQueryObjectui64vEXT),
+    SYM(DrawBuffersEXT),
+    SYM(EnableiEXT),
+    SYM(DisableiEXT),
+    SYM(BlendEquationiEXT),
+    SYM(BlendEquationSeparateiEXT),
+    SYM(BlendFunciEXT),
+    SYM(BlendFuncSeparateiEXT),
+    SYM(ColorMaskiEXT),
+    SYM(IsEnablediEXT),
+    SYM(DrawElementsBaseVertexEXT),
+    SYM(DrawRangeElementsBaseVertexEXT),
+    SYM(DrawElementsInstancedBaseVertexEXT),
+    SYM(MultiDrawElementsBaseVertexEXT),
+    SYM(DrawArraysInstancedEXT),
+    SYM(DrawElementsInstancedEXT),
+    SYM(FramebufferTextureEXT),
+    SYM(VertexAttribDivisorEXT),
+    SYM(MapBufferRangeEXT),
+    SYM(FlushMappedBufferRangeEXT),
+    SYM(MultiDrawArraysEXT),
+    SYM(MultiDrawElementsEXT),
+    SYM(MultiDrawArraysIndirectEXT),
+    SYM(MultiDrawElementsIndirectEXT),
+    SYM(RenderbufferStorageMultisampleEXT),
+    SYM(FramebufferTexture2DMultisampleEXT),
+    SYM(ReadBufferIndexedEXT),
+    SYM(DrawBuffersIndexedEXT),
+    SYM(GetIntegeri_vEXT),
+    SYM(PolygonOffsetClampEXT),
+    SYM(PrimitiveBoundingBoxEXT),
+    SYM(RasterSamplesEXT),
+    SYM(GetGraphicsResetStatusEXT),
+    SYM(ReadnPixelsEXT),
+    SYM(GetnUniformfvEXT),
+    SYM(GetnUniformivEXT),
+    SYM(ActiveShaderProgramEXT),
+    SYM(BindProgramPipelineEXT),
+    SYM(CreateShaderProgramvEXT),
+    SYM(DeleteProgramPipelinesEXT),
+    SYM(GenProgramPipelinesEXT),
+    SYM(GetProgramPipelineInfoLogEXT),
+    SYM(GetProgramPipelineivEXT),
+    SYM(IsProgramPipelineEXT),
+    SYM(ProgramParameteriEXT),
+    SYM(ProgramUniform1fEXT),
+    SYM(ProgramUniform1fvEXT),
+    SYM(ProgramUniform1iEXT),
+    SYM(ProgramUniform1ivEXT),
+    SYM(ProgramUniform2fEXT),
+    SYM(ProgramUniform2fvEXT),
+    SYM(ProgramUniform2iEXT),
+    SYM(ProgramUniform2ivEXT),
+    SYM(ProgramUniform3fEXT),
+    SYM(ProgramUniform3fvEXT),
+    SYM(ProgramUniform3iEXT),
+    SYM(ProgramUniform3ivEXT),
+    SYM(ProgramUniform4fEXT),
+    SYM(ProgramUniform4fvEXT),
+    SYM(ProgramUniform4iEXT),
+    SYM(ProgramUniform4ivEXT),
+    SYM(ProgramUniformMatrix2fvEXT),
+    SYM(ProgramUniformMatrix3fvEXT),
+    SYM(ProgramUniformMatrix4fvEXT),
+    SYM(UseProgramStagesEXT),
+    SYM(ValidateProgramPipelineEXT),
+    SYM(ProgramUniform1uiEXT),
+    SYM(ProgramUniform2uiEXT),
+    SYM(ProgramUniform3uiEXT),
+    SYM(ProgramUniform4uiEXT),
+    SYM(ProgramUniform1uivEXT),
+    SYM(ProgramUniform2uivEXT),
+    SYM(ProgramUniform3uivEXT),
+    SYM(ProgramUniform4uivEXT),
+    SYM(ProgramUniformMatrix2x3fvEXT),
+    SYM(ProgramUniformMatrix3x2fvEXT),
+    SYM(ProgramUniformMatrix2x4fvEXT),
+    SYM(ProgramUniformMatrix4x2fvEXT),
+    SYM(ProgramUniformMatrix3x4fvEXT),
+    SYM(ProgramUniformMatrix4x3fvEXT),
+    SYM(FramebufferPixelLocalStorageSizeEXT),
+    SYM(GetFramebufferPixelLocalStorageSizeEXT),
+    SYM(ClearPixelLocalStorageuiEXT),
+    SYM(TexPageCommitmentEXT),
+    SYM(PatchParameteriEXT),
+    SYM(TexParameterIivEXT),
+    SYM(TexParameterIuivEXT),
+    SYM(GetTexParameterIivEXT),
+    SYM(GetTexParameterIuivEXT),
+    SYM(SamplerParameterIivEXT),
+    SYM(SamplerParameterIuivEXT),
+    SYM(GetSamplerParameterIivEXT),
+    SYM(GetSamplerParameterIuivEXT),
+    SYM(TexBufferEXT),
+    SYM(TexBufferRangeEXT),
+    SYM(TexStorage1DEXT),
+    SYM(TexStorage2DEXT),
+    SYM(TexStorage3DEXT),
+    SYM(TextureStorage1DEXT),
+    SYM(TextureStorage2DEXT),
+    SYM(TextureStorage3DEXT),
+    SYM(TextureViewEXT),
+    SYM(FramebufferTextureMultiviewOVR),
+    SYM(FramebufferTextureMultisampleMultiviewOVR),
+
+    { NULL, NULL },
+};
+RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
+RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
+RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
+RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
+RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
+RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
+RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
+RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
+RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
+RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
+RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
+RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
+RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
+RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
+RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
+RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
+RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
+RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
+RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
+RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
+RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
+RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
+RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
+RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
+RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
+RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
+RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
+RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
+RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
+RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
+RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
+RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
+RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
+RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
+RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
+RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
+RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
+RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
+RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
+RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
+RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
+RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
+RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
+RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
+RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
+RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
+RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
+RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
+RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
+RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
+RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
+RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
+RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
+RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
+RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
+RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
+RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
+RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
+RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
+RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
+RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
+RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
+RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
+RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
+RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
+RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
+RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
+RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
+RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
+RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
+RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
+RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
+RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
+RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
+RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
+RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
+RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
+RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
+RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
+RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
+RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
+RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
+RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
+RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
+RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
+RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
+RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
+RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
+RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
+RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
+RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
+RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
+RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
+RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
+RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;
+RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;
+RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
+RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
+RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
+RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
+RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
+RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
+RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
+RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
+RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
+RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
+RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
+RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
+RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
+RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
+RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
+RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
+RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
+RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
+RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
+RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
+RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
+RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
+RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
+RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
+RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
+RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
+RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
+RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
+RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
+RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
+RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
+RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
+RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
+RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
+RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
+RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
+RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
+RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
+RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
+RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
+RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
+RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
+RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
+RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
+RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
+RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
+RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
+RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
+RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
+RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
+RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
+RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
+RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
+RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
+RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
+RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
+RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
+RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
+RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
+RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
+RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
+RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
+RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
+RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
+RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
+RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
+RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
+RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
+RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
+RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
+RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
+RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
+RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
+RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
+RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
+RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
+RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
+RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
+RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
+RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
+RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
+RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
+RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
+RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
+RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
+RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
+RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
+RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
+RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
+RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
+RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
+RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
+RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
diff --git a/deps/libretro-common/glsym/glsym_gl.c b/deps/libretro-common/glsym/glsym_gl.c
new file mode 100644 (file)
index 0000000..a5ce04e
--- /dev/null
@@ -0,0 +1,2541 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsym).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stddef.h>
+
+#include <glsym/glsym.h>
+
+#define SYM(x) { "gl" #x, (void*)&(gl##x) }
+
+const struct rglgen_sym_map rglgen_symbol_map[] = {
+#ifdef HAVE_LIBNX
+    SYM(ClearIndex),
+    SYM(ClearColor),
+    SYM(Clear),
+    SYM(IndexMask),
+    SYM(ColorMask),
+    SYM(AlphaFunc),
+    SYM(BlendFunc),
+    SYM(LogicOp),
+    SYM(CullFace),
+    SYM(FrontFace),
+    SYM(PointSize),
+    SYM(LineWidth),
+    SYM(LineStipple),
+    SYM(PolygonMode),
+    SYM(PolygonOffset),
+    SYM(PolygonStipple),
+    SYM(GetPolygonStipple),
+    SYM(EdgeFlag),
+    SYM(EdgeFlagv),
+    SYM(Scissor),
+    SYM(ClipPlane),
+    SYM(GetClipPlane),
+    SYM(DrawBuffer),
+    SYM(ReadBuffer),
+    SYM(Enable),
+    SYM(Disable),
+    SYM(IsEnabled),
+    SYM(EnableClientState),
+    SYM(DisableClientState),
+    SYM(GetBooleanv),
+    SYM(GetDoublev),
+    SYM(GetFloatv),
+    SYM(GetIntegerv),
+    SYM(PushAttrib),
+    SYM(PopAttrib),
+    SYM(PushClientAttrib),
+    SYM(PopClientAttrib),
+    SYM(RenderMode),
+    SYM(GetError),
+    SYM(GetString),
+    SYM(Finish),
+    SYM(Flush),
+    SYM(Hint),
+    SYM(ClearDepth),
+    SYM(DepthFunc),
+    SYM(DepthMask),
+    SYM(DepthRange),
+    SYM(ClearAccum),
+    SYM(Accum),
+    SYM(MatrixMode),
+    SYM(Ortho),
+    SYM(Frustum),
+    SYM(Viewport),
+    SYM(PushMatrix),
+    SYM(PopMatrix),
+    SYM(LoadIdentity),
+    SYM(LoadMatrixd),
+    SYM(LoadMatrixf),
+    SYM(MultMatrixd),
+    SYM(MultMatrixf),
+    SYM(Rotated),
+    SYM(Rotatef),
+    SYM(Scaled),
+    SYM(Scalef),
+    SYM(Translated),
+    SYM(Translatef),
+    SYM(IsList),
+    SYM(DeleteLists),
+    SYM(GenLists),
+    SYM(NewList),
+    SYM(EndList),
+    SYM(CallList),
+    SYM(CallLists),
+    SYM(ListBase),
+    SYM(Begin),
+    SYM(End),
+    SYM(Vertex2d),
+    SYM(Vertex2f),
+    SYM(Vertex2i),
+    SYM(Vertex2s),
+    SYM(Vertex3d),
+    SYM(Vertex3f),
+    SYM(Vertex3i),
+    SYM(Vertex3s),
+    SYM(Vertex4d),
+    SYM(Vertex4f),
+    SYM(Vertex4i),
+    SYM(Vertex4s),
+    SYM(Vertex2dv),
+    SYM(Vertex2fv),
+    SYM(Vertex2iv),
+    SYM(Vertex2sv),
+    SYM(Vertex3dv),
+    SYM(Vertex3fv),
+    SYM(Vertex3iv),
+    SYM(Vertex3sv),
+    SYM(Vertex4dv),
+    SYM(Vertex4fv),
+    SYM(Vertex4iv),
+    SYM(Vertex4sv),
+    SYM(Normal3b),
+    SYM(Normal3d),
+    SYM(Normal3f),
+    SYM(Normal3i),
+    SYM(Normal3s),
+    SYM(Normal3bv),
+    SYM(Normal3dv),
+    SYM(Normal3fv),
+    SYM(Normal3iv),
+    SYM(Normal3sv),
+    SYM(Indexd),
+    SYM(Indexf),
+    SYM(Indexi),
+    SYM(Indexs),
+    SYM(Indexub),
+    SYM(Indexdv),
+    SYM(Indexfv),
+    SYM(Indexiv),
+    SYM(Indexsv),
+    SYM(Indexubv),
+    SYM(Color3b),
+    SYM(Color3d),
+    SYM(Color3f),
+    SYM(Color3i),
+    SYM(Color3s),
+    SYM(Color3ub),
+    SYM(Color3ui),
+    SYM(Color3us),
+    SYM(Color4b),
+    SYM(Color4d),
+    SYM(Color4f),
+    SYM(Color4i),
+    SYM(Color4s),
+    SYM(Color4ub),
+    SYM(Color4ui),
+    SYM(Color4us),
+    SYM(Color3bv),
+    SYM(Color3dv),
+    SYM(Color3fv),
+    SYM(Color3iv),
+    SYM(Color3sv),
+    SYM(Color3ubv),
+    SYM(Color3uiv),
+    SYM(Color3usv),
+    SYM(Color4bv),
+    SYM(Color4dv),
+    SYM(Color4fv),
+    SYM(Color4iv),
+    SYM(Color4sv),
+    SYM(Color4ubv),
+    SYM(Color4uiv),
+    SYM(Color4usv),
+    SYM(TexCoord1d),
+    SYM(TexCoord1f),
+    SYM(TexCoord1i),
+    SYM(TexCoord1s),
+    SYM(TexCoord2d),
+    SYM(TexCoord2f),
+    SYM(TexCoord2i),
+    SYM(TexCoord2s),
+    SYM(TexCoord3d),
+    SYM(TexCoord3f),
+    SYM(TexCoord3i),
+    SYM(TexCoord3s),
+    SYM(TexCoord4d),
+    SYM(TexCoord4f),
+    SYM(TexCoord4i),
+    SYM(TexCoord4s),
+    SYM(TexCoord1dv),
+    SYM(TexCoord1fv),
+    SYM(TexCoord1iv),
+    SYM(TexCoord1sv),
+    SYM(TexCoord2dv),
+    SYM(TexCoord2fv),
+    SYM(TexCoord2iv),
+    SYM(TexCoord2sv),
+    SYM(TexCoord3dv),
+    SYM(TexCoord3fv),
+    SYM(TexCoord3iv),
+    SYM(TexCoord3sv),
+    SYM(TexCoord4dv),
+    SYM(TexCoord4fv),
+    SYM(TexCoord4iv),
+    SYM(TexCoord4sv),
+    SYM(RasterPos2d),
+    SYM(RasterPos2f),
+    SYM(RasterPos2i),
+    SYM(RasterPos2s),
+    SYM(RasterPos3d),
+    SYM(RasterPos3f),
+    SYM(RasterPos3i),
+    SYM(RasterPos3s),
+    SYM(RasterPos4d),
+    SYM(RasterPos4f),
+    SYM(RasterPos4i),
+    SYM(RasterPos4s),
+    SYM(RasterPos2dv),
+    SYM(RasterPos2fv),
+    SYM(RasterPos2iv),
+    SYM(RasterPos2sv),
+    SYM(RasterPos3dv),
+    SYM(RasterPos3fv),
+    SYM(RasterPos3iv),
+    SYM(RasterPos3sv),
+    SYM(RasterPos4dv),
+    SYM(RasterPos4fv),
+    SYM(RasterPos4iv),
+    SYM(RasterPos4sv),
+    SYM(Rectd),
+    SYM(Rectf),
+    SYM(Recti),
+    SYM(Rects),
+    SYM(Rectdv),
+    SYM(Rectfv),
+    SYM(Rectiv),
+    SYM(Rectsv),
+    SYM(VertexPointer),
+    SYM(NormalPointer),
+    SYM(ColorPointer),
+    SYM(IndexPointer),
+    SYM(TexCoordPointer),
+    SYM(EdgeFlagPointer),
+    SYM(GetPointerv),
+    SYM(ArrayElement),
+    SYM(DrawArrays),
+    SYM(DrawElements),
+    SYM(InterleavedArrays),
+    SYM(ShadeModel),
+    SYM(Lightf),
+    SYM(Lighti),
+    SYM(Lightfv),
+    SYM(Lightiv),
+    SYM(GetLightfv),
+    SYM(GetLightiv),
+    SYM(LightModelf),
+    SYM(LightModeli),
+    SYM(LightModelfv),
+    SYM(LightModeliv),
+    SYM(Materialf),
+    SYM(Materiali),
+    SYM(Materialfv),
+    SYM(Materialiv),
+    SYM(GetMaterialfv),
+    SYM(GetMaterialiv),
+    SYM(ColorMaterial),
+    SYM(PixelZoom),
+    SYM(PixelStoref),
+    SYM(PixelStorei),
+    SYM(PixelTransferf),
+    SYM(PixelTransferi),
+    SYM(PixelMapfv),
+    SYM(PixelMapuiv),
+    SYM(PixelMapusv),
+    SYM(GetPixelMapfv),
+    SYM(GetPixelMapuiv),
+    SYM(GetPixelMapusv),
+    SYM(Bitmap),
+    SYM(ReadPixels),
+    SYM(DrawPixels),
+    SYM(CopyPixels),
+    SYM(StencilFunc),
+    SYM(StencilMask),
+    SYM(StencilOp),
+    SYM(ClearStencil),
+    SYM(TexGend),
+    SYM(TexGenf),
+    SYM(TexGeni),
+    SYM(TexGendv),
+    SYM(TexGenfv),
+    SYM(TexGeniv),
+    SYM(GetTexGendv),
+    SYM(GetTexGenfv),
+    SYM(GetTexGeniv),
+    SYM(TexEnvf),
+    SYM(TexEnvi),
+    SYM(TexEnvfv),
+    SYM(TexEnviv),
+    SYM(GetTexEnvfv),
+    SYM(GetTexEnviv),
+    SYM(TexParameterf),
+    SYM(TexParameteri),
+    SYM(TexParameterfv),
+    SYM(TexParameteriv),
+    SYM(GetTexParameterfv),
+    SYM(GetTexParameteriv),
+    SYM(GetTexLevelParameterfv),
+    SYM(GetTexLevelParameteriv),
+    SYM(TexImage1D),
+    SYM(TexImage2D),
+    SYM(GetTexImage),
+    SYM(GenTextures),
+    SYM(DeleteTextures),
+    SYM(BindTexture),
+    SYM(PrioritizeTextures),
+    SYM(AreTexturesResident),
+    SYM(IsTexture),
+    SYM(TexSubImage1D),
+    SYM(TexSubImage2D),
+    SYM(CopyTexImage1D),
+    SYM(CopyTexImage2D),
+    SYM(CopyTexSubImage1D),
+    SYM(CopyTexSubImage2D),
+    SYM(Map1d),
+    SYM(Map1f),
+    SYM(Map2d),
+    SYM(Map2f),
+    SYM(GetMapdv),
+    SYM(GetMapfv),
+    SYM(GetMapiv),
+    SYM(EvalCoord1d),
+    SYM(EvalCoord1f),
+    SYM(EvalCoord1dv),
+    SYM(EvalCoord1fv),
+    SYM(EvalCoord2d),
+    SYM(EvalCoord2f),
+    SYM(EvalCoord2dv),
+    SYM(EvalCoord2fv),
+    SYM(MapGrid1d),
+    SYM(MapGrid1f),
+    SYM(MapGrid2d),
+    SYM(MapGrid2f),
+    SYM(EvalPoint1),
+    SYM(EvalPoint2),
+    SYM(EvalMesh1),
+    SYM(EvalMesh2),
+    SYM(Fogf),
+    SYM(Fogi),
+    SYM(Fogfv),
+    SYM(Fogiv),
+    SYM(FeedbackBuffer),
+    SYM(PassThrough),
+    SYM(SelectBuffer),
+    SYM(InitNames),
+    SYM(LoadName),
+    SYM(PushName),
+    SYM(PopName),
+    SYM(DrawRangeElements),
+    SYM(TexImage3D),
+    SYM(TexSubImage3D),
+    SYM(CopyTexSubImage3D),
+    SYM(ColorTable),
+    SYM(ColorSubTable),
+    SYM(ColorTableParameteriv),
+    SYM(ColorTableParameterfv),
+    SYM(CopyColorSubTable),
+    SYM(CopyColorTable),
+    SYM(GetColorTable),
+    SYM(GetColorTableParameterfv),
+    SYM(GetColorTableParameteriv),
+    SYM(BlendEquation),
+    SYM(BlendColor),
+    SYM(Histogram),
+    SYM(ResetHistogram),
+    SYM(GetHistogram),
+    SYM(GetHistogramParameterfv),
+    SYM(GetHistogramParameteriv),
+    SYM(Minmax),
+    SYM(ResetMinmax),
+    SYM(GetMinmax),
+    SYM(GetMinmaxParameterfv),
+    SYM(GetMinmaxParameteriv),
+    SYM(ConvolutionFilter1D),
+    SYM(ConvolutionFilter2D),
+    SYM(ConvolutionParameterf),
+    SYM(ConvolutionParameterfv),
+    SYM(ConvolutionParameteri),
+    SYM(ConvolutionParameteriv),
+    SYM(CopyConvolutionFilter1D),
+    SYM(CopyConvolutionFilter2D),
+    SYM(GetConvolutionFilter),
+    SYM(GetConvolutionParameterfv),
+    SYM(GetConvolutionParameteriv),
+    SYM(SeparableFilter2D),
+    SYM(GetSeparableFilter),
+    SYM(ActiveTexture),
+    SYM(ClientActiveTexture),
+    SYM(CompressedTexImage1D),
+    SYM(CompressedTexImage2D),
+    SYM(CompressedTexImage3D),
+    SYM(CompressedTexSubImage1D),
+    SYM(CompressedTexSubImage2D),
+    SYM(CompressedTexSubImage3D),
+    SYM(GetCompressedTexImage),
+    SYM(MultiTexCoord1d),
+    SYM(MultiTexCoord1dv),
+    SYM(MultiTexCoord1f),
+    SYM(MultiTexCoord1fv),
+    SYM(MultiTexCoord1i),
+    SYM(MultiTexCoord1iv),
+    SYM(MultiTexCoord1s),
+    SYM(MultiTexCoord1sv),
+    SYM(MultiTexCoord2d),
+    SYM(MultiTexCoord2dv),
+    SYM(MultiTexCoord2f),
+    SYM(MultiTexCoord2fv),
+    SYM(MultiTexCoord2i),
+    SYM(MultiTexCoord2iv),
+    SYM(MultiTexCoord2s),
+    SYM(MultiTexCoord2sv),
+    SYM(MultiTexCoord3d),
+    SYM(MultiTexCoord3dv),
+    SYM(MultiTexCoord3f),
+    SYM(MultiTexCoord3fv),
+    SYM(MultiTexCoord3i),
+    SYM(MultiTexCoord3iv),
+    SYM(MultiTexCoord3s),
+    SYM(MultiTexCoord3sv),
+    SYM(MultiTexCoord4d),
+    SYM(MultiTexCoord4dv),
+    SYM(MultiTexCoord4f),
+    SYM(MultiTexCoord4fv),
+    SYM(MultiTexCoord4i),
+    SYM(MultiTexCoord4iv),
+    SYM(MultiTexCoord4s),
+    SYM(MultiTexCoord4sv),
+    SYM(LoadTransposeMatrixd),
+    SYM(LoadTransposeMatrixf),
+    SYM(MultTransposeMatrixd),
+    SYM(MultTransposeMatrixf),
+    SYM(SampleCoverage),
+    SYM(ActiveTextureARB),
+    SYM(ClientActiveTextureARB),
+    SYM(MultiTexCoord1dARB),
+    SYM(MultiTexCoord1dvARB),
+    SYM(MultiTexCoord1fARB),
+    SYM(MultiTexCoord1fvARB),
+    SYM(MultiTexCoord1iARB),
+    SYM(MultiTexCoord1ivARB),
+    SYM(MultiTexCoord1sARB),
+    SYM(MultiTexCoord1svARB),
+    SYM(MultiTexCoord2dARB),
+    SYM(MultiTexCoord2dvARB),
+    SYM(MultiTexCoord2fARB),
+    SYM(MultiTexCoord2fvARB),
+    SYM(MultiTexCoord2iARB),
+    SYM(MultiTexCoord2ivARB),
+    SYM(MultiTexCoord2sARB),
+    SYM(MultiTexCoord2svARB),
+    SYM(MultiTexCoord3dARB),
+    SYM(MultiTexCoord3dvARB),
+    SYM(MultiTexCoord3fARB),
+    SYM(MultiTexCoord3fvARB),
+    SYM(MultiTexCoord3iARB),
+    SYM(MultiTexCoord3ivARB),
+    SYM(MultiTexCoord3sARB),
+    SYM(MultiTexCoord3svARB),
+    SYM(MultiTexCoord4dARB),
+    SYM(MultiTexCoord4dvARB),
+    SYM(MultiTexCoord4fARB),
+    SYM(MultiTexCoord4fvARB),
+    SYM(MultiTexCoord4iARB),
+    SYM(MultiTexCoord4ivARB),
+    SYM(MultiTexCoord4sARB),
+    SYM(MultiTexCoord4svARB),
+    SYM(EGLImageTargetTexture2DOES),
+    SYM(EGLImageTargetRenderbufferStorageOES),
+#endif
+
+    SYM(DrawRangeElements),
+    SYM(TexImage3D),
+    SYM(TexSubImage3D),
+    SYM(CopyTexSubImage3D),
+    SYM(ActiveTexture),
+    SYM(SampleCoverage),
+    SYM(CompressedTexImage3D),
+    SYM(CompressedTexImage2D),
+    SYM(CompressedTexImage1D),
+    SYM(CompressedTexSubImage3D),
+    SYM(CompressedTexSubImage2D),
+    SYM(CompressedTexSubImage1D),
+    SYM(GetCompressedTexImage),
+    SYM(ClientActiveTexture),
+    SYM(MultiTexCoord1d),
+    SYM(MultiTexCoord1dv),
+    SYM(MultiTexCoord1f),
+    SYM(MultiTexCoord1fv),
+    SYM(MultiTexCoord1i),
+    SYM(MultiTexCoord1iv),
+    SYM(MultiTexCoord1s),
+    SYM(MultiTexCoord1sv),
+    SYM(MultiTexCoord2d),
+    SYM(MultiTexCoord2dv),
+    SYM(MultiTexCoord2f),
+    SYM(MultiTexCoord2fv),
+    SYM(MultiTexCoord2i),
+    SYM(MultiTexCoord2iv),
+    SYM(MultiTexCoord2s),
+    SYM(MultiTexCoord2sv),
+    SYM(MultiTexCoord3d),
+    SYM(MultiTexCoord3dv),
+    SYM(MultiTexCoord3f),
+    SYM(MultiTexCoord3fv),
+    SYM(MultiTexCoord3i),
+    SYM(MultiTexCoord3iv),
+    SYM(MultiTexCoord3s),
+    SYM(MultiTexCoord3sv),
+    SYM(MultiTexCoord4d),
+    SYM(MultiTexCoord4dv),
+    SYM(MultiTexCoord4f),
+    SYM(MultiTexCoord4fv),
+    SYM(MultiTexCoord4i),
+    SYM(MultiTexCoord4iv),
+    SYM(MultiTexCoord4s),
+    SYM(MultiTexCoord4sv),
+    SYM(LoadTransposeMatrixf),
+    SYM(LoadTransposeMatrixd),
+    SYM(MultTransposeMatrixf),
+    SYM(MultTransposeMatrixd),
+    SYM(BlendFuncSeparate),
+    SYM(MultiDrawArrays),
+    SYM(MultiDrawElements),
+    SYM(PointParameterf),
+    SYM(PointParameterfv),
+    SYM(PointParameteri),
+    SYM(PointParameteriv),
+    SYM(FogCoordf),
+    SYM(FogCoordfv),
+    SYM(FogCoordd),
+    SYM(FogCoorddv),
+    SYM(FogCoordPointer),
+    SYM(SecondaryColor3b),
+    SYM(SecondaryColor3bv),
+    SYM(SecondaryColor3d),
+    SYM(SecondaryColor3dv),
+    SYM(SecondaryColor3f),
+    SYM(SecondaryColor3fv),
+    SYM(SecondaryColor3i),
+    SYM(SecondaryColor3iv),
+    SYM(SecondaryColor3s),
+    SYM(SecondaryColor3sv),
+    SYM(SecondaryColor3ub),
+    SYM(SecondaryColor3ubv),
+    SYM(SecondaryColor3ui),
+    SYM(SecondaryColor3uiv),
+    SYM(SecondaryColor3us),
+    SYM(SecondaryColor3usv),
+    SYM(SecondaryColorPointer),
+    SYM(WindowPos2d),
+    SYM(WindowPos2dv),
+    SYM(WindowPos2f),
+    SYM(WindowPos2fv),
+    SYM(WindowPos2i),
+    SYM(WindowPos2iv),
+    SYM(WindowPos2s),
+    SYM(WindowPos2sv),
+    SYM(WindowPos3d),
+    SYM(WindowPos3dv),
+    SYM(WindowPos3f),
+    SYM(WindowPos3fv),
+    SYM(WindowPos3i),
+    SYM(WindowPos3iv),
+    SYM(WindowPos3s),
+    SYM(WindowPos3sv),
+    SYM(BlendColor),
+    SYM(BlendEquation),
+    SYM(GenQueries),
+    SYM(DeleteQueries),
+    SYM(IsQuery),
+    SYM(BeginQuery),
+    SYM(EndQuery),
+    SYM(GetQueryiv),
+    SYM(GetQueryObjectiv),
+    SYM(GetQueryObjectuiv),
+    SYM(BindBuffer),
+    SYM(DeleteBuffers),
+    SYM(GenBuffers),
+    SYM(IsBuffer),
+    SYM(BufferData),
+    SYM(BufferSubData),
+    SYM(GetBufferSubData),
+    SYM(MapBuffer),
+    SYM(UnmapBuffer),
+    SYM(GetBufferParameteriv),
+    SYM(GetBufferPointerv),
+    SYM(BlendEquationSeparate),
+    SYM(DrawBuffers),
+    SYM(StencilOpSeparate),
+    SYM(StencilFuncSeparate),
+    SYM(StencilMaskSeparate),
+    SYM(AttachShader),
+    SYM(BindAttribLocation),
+    SYM(CompileShader),
+    SYM(CreateProgram),
+    SYM(CreateShader),
+    SYM(DeleteProgram),
+    SYM(DeleteShader),
+    SYM(DetachShader),
+    SYM(DisableVertexAttribArray),
+    SYM(EnableVertexAttribArray),
+    SYM(GetActiveAttrib),
+    SYM(GetActiveUniform),
+    SYM(GetAttachedShaders),
+    SYM(GetAttribLocation),
+    SYM(GetProgramiv),
+    SYM(GetProgramInfoLog),
+    SYM(GetShaderiv),
+    SYM(GetShaderInfoLog),
+    SYM(GetShaderSource),
+    SYM(GetUniformLocation),
+    SYM(GetUniformfv),
+    SYM(GetUniformiv),
+    SYM(GetVertexAttribdv),
+    SYM(GetVertexAttribfv),
+    SYM(GetVertexAttribiv),
+    SYM(GetVertexAttribPointerv),
+    SYM(IsProgram),
+    SYM(IsShader),
+    SYM(LinkProgram),
+    SYM(ShaderSource),
+    SYM(UseProgram),
+    SYM(Uniform1f),
+    SYM(Uniform2f),
+    SYM(Uniform3f),
+    SYM(Uniform4f),
+    SYM(Uniform1i),
+    SYM(Uniform2i),
+    SYM(Uniform3i),
+    SYM(Uniform4i),
+    SYM(Uniform1fv),
+    SYM(Uniform2fv),
+    SYM(Uniform3fv),
+    SYM(Uniform4fv),
+    SYM(Uniform1iv),
+    SYM(Uniform2iv),
+    SYM(Uniform3iv),
+    SYM(Uniform4iv),
+    SYM(UniformMatrix2fv),
+    SYM(UniformMatrix3fv),
+    SYM(UniformMatrix4fv),
+    SYM(ValidateProgram),
+    SYM(VertexAttrib1d),
+    SYM(VertexAttrib1dv),
+    SYM(VertexAttrib1f),
+    SYM(VertexAttrib1fv),
+    SYM(VertexAttrib1s),
+    SYM(VertexAttrib1sv),
+    SYM(VertexAttrib2d),
+    SYM(VertexAttrib2dv),
+    SYM(VertexAttrib2f),
+    SYM(VertexAttrib2fv),
+    SYM(VertexAttrib2s),
+    SYM(VertexAttrib2sv),
+    SYM(VertexAttrib3d),
+    SYM(VertexAttrib3dv),
+    SYM(VertexAttrib3f),
+    SYM(VertexAttrib3fv),
+    SYM(VertexAttrib3s),
+    SYM(VertexAttrib3sv),
+    SYM(VertexAttrib4Nbv),
+    SYM(VertexAttrib4Niv),
+    SYM(VertexAttrib4Nsv),
+    SYM(VertexAttrib4Nub),
+    SYM(VertexAttrib4Nubv),
+    SYM(VertexAttrib4Nuiv),
+    SYM(VertexAttrib4Nusv),
+    SYM(VertexAttrib4bv),
+    SYM(VertexAttrib4d),
+    SYM(VertexAttrib4dv),
+    SYM(VertexAttrib4f),
+    SYM(VertexAttrib4fv),
+    SYM(VertexAttrib4iv),
+    SYM(VertexAttrib4s),
+    SYM(VertexAttrib4sv),
+    SYM(VertexAttrib4ubv),
+    SYM(VertexAttrib4uiv),
+    SYM(VertexAttrib4usv),
+    SYM(VertexAttribPointer),
+    SYM(UniformMatrix2x3fv),
+    SYM(UniformMatrix3x2fv),
+    SYM(UniformMatrix2x4fv),
+    SYM(UniformMatrix4x2fv),
+    SYM(UniformMatrix3x4fv),
+    SYM(UniformMatrix4x3fv),
+    SYM(ColorMaski),
+    SYM(GetBooleani_v),
+    SYM(GetIntegeri_v),
+    SYM(Enablei),
+    SYM(Disablei),
+    SYM(IsEnabledi),
+    SYM(BeginTransformFeedback),
+    SYM(EndTransformFeedback),
+    SYM(BindBufferRange),
+    SYM(BindBufferBase),
+    SYM(TransformFeedbackVaryings),
+    SYM(GetTransformFeedbackVarying),
+    SYM(ClampColor),
+    SYM(BeginConditionalRender),
+    SYM(EndConditionalRender),
+    SYM(VertexAttribIPointer),
+    SYM(GetVertexAttribIiv),
+    SYM(GetVertexAttribIuiv),
+    SYM(VertexAttribI1i),
+    SYM(VertexAttribI2i),
+    SYM(VertexAttribI3i),
+    SYM(VertexAttribI4i),
+    SYM(VertexAttribI1ui),
+    SYM(VertexAttribI2ui),
+    SYM(VertexAttribI3ui),
+    SYM(VertexAttribI4ui),
+    SYM(VertexAttribI1iv),
+    SYM(VertexAttribI2iv),
+    SYM(VertexAttribI3iv),
+    SYM(VertexAttribI4iv),
+    SYM(VertexAttribI1uiv),
+    SYM(VertexAttribI2uiv),
+    SYM(VertexAttribI3uiv),
+    SYM(VertexAttribI4uiv),
+    SYM(VertexAttribI4bv),
+    SYM(VertexAttribI4sv),
+    SYM(VertexAttribI4ubv),
+    SYM(VertexAttribI4usv),
+    SYM(GetUniformuiv),
+    SYM(BindFragDataLocation),
+    SYM(GetFragDataLocation),
+    SYM(Uniform1ui),
+    SYM(Uniform2ui),
+    SYM(Uniform3ui),
+    SYM(Uniform4ui),
+    SYM(Uniform1uiv),
+    SYM(Uniform2uiv),
+    SYM(Uniform3uiv),
+    SYM(Uniform4uiv),
+    SYM(TexParameterIiv),
+    SYM(TexParameterIuiv),
+    SYM(GetTexParameterIiv),
+    SYM(GetTexParameterIuiv),
+    SYM(ClearBufferiv),
+    SYM(ClearBufferuiv),
+    SYM(ClearBufferfv),
+    SYM(ClearBufferfi),
+    SYM(GetStringi),
+    SYM(IsRenderbuffer),
+    SYM(BindRenderbuffer),
+    SYM(DeleteRenderbuffers),
+    SYM(GenRenderbuffers),
+    SYM(RenderbufferStorage),
+    SYM(GetRenderbufferParameteriv),
+    SYM(IsFramebuffer),
+    SYM(BindFramebuffer),
+    SYM(DeleteFramebuffers),
+    SYM(GenFramebuffers),
+    SYM(CheckFramebufferStatus),
+    SYM(FramebufferTexture1D),
+    SYM(FramebufferTexture2D),
+    SYM(FramebufferTexture3D),
+    SYM(FramebufferRenderbuffer),
+    SYM(GetFramebufferAttachmentParameteriv),
+    SYM(GenerateMipmap),
+    SYM(BlitFramebuffer),
+    SYM(RenderbufferStorageMultisample),
+    SYM(FramebufferTextureLayer),
+    SYM(MapBufferRange),
+    SYM(FlushMappedBufferRange),
+    SYM(BindVertexArray),
+    SYM(DeleteVertexArrays),
+    SYM(GenVertexArrays),
+    SYM(IsVertexArray),
+    SYM(DrawArraysInstanced),
+    SYM(DrawElementsInstanced),
+    SYM(TexBuffer),
+    SYM(PrimitiveRestartIndex),
+    SYM(CopyBufferSubData),
+    SYM(GetUniformIndices),
+    SYM(GetActiveUniformsiv),
+    SYM(GetActiveUniformName),
+    SYM(GetUniformBlockIndex),
+    SYM(GetActiveUniformBlockiv),
+    SYM(GetActiveUniformBlockName),
+    SYM(UniformBlockBinding),
+    SYM(DrawElementsBaseVertex),
+    SYM(DrawRangeElementsBaseVertex),
+    SYM(DrawElementsInstancedBaseVertex),
+    SYM(MultiDrawElementsBaseVertex),
+    SYM(ProvokingVertex),
+    SYM(FenceSync),
+    SYM(IsSync),
+    SYM(DeleteSync),
+    SYM(ClientWaitSync),
+    SYM(WaitSync),
+    SYM(GetInteger64v),
+    SYM(GetSynciv),
+    SYM(GetInteger64i_v),
+    SYM(GetBufferParameteri64v),
+    SYM(FramebufferTexture),
+    SYM(TexImage2DMultisample),
+    SYM(TexImage3DMultisample),
+    SYM(GetMultisamplefv),
+    SYM(SampleMaski),
+    SYM(BindFragDataLocationIndexed),
+    SYM(GetFragDataIndex),
+    SYM(GenSamplers),
+    SYM(DeleteSamplers),
+    SYM(IsSampler),
+    SYM(BindSampler),
+    SYM(SamplerParameteri),
+    SYM(SamplerParameteriv),
+    SYM(SamplerParameterf),
+    SYM(SamplerParameterfv),
+    SYM(SamplerParameterIiv),
+    SYM(SamplerParameterIuiv),
+    SYM(GetSamplerParameteriv),
+    SYM(GetSamplerParameterIiv),
+    SYM(GetSamplerParameterfv),
+    SYM(GetSamplerParameterIuiv),
+    SYM(QueryCounter),
+    SYM(GetQueryObjecti64v),
+    SYM(GetQueryObjectui64v),
+    SYM(VertexAttribDivisor),
+    SYM(VertexAttribP1ui),
+    SYM(VertexAttribP1uiv),
+    SYM(VertexAttribP2ui),
+    SYM(VertexAttribP2uiv),
+    SYM(VertexAttribP3ui),
+    SYM(VertexAttribP3uiv),
+    SYM(VertexAttribP4ui),
+    SYM(VertexAttribP4uiv),
+    SYM(VertexP2ui),
+    SYM(VertexP2uiv),
+    SYM(VertexP3ui),
+    SYM(VertexP3uiv),
+    SYM(VertexP4ui),
+    SYM(VertexP4uiv),
+    SYM(TexCoordP1ui),
+    SYM(TexCoordP1uiv),
+    SYM(TexCoordP2ui),
+    SYM(TexCoordP2uiv),
+    SYM(TexCoordP3ui),
+    SYM(TexCoordP3uiv),
+    SYM(TexCoordP4ui),
+    SYM(TexCoordP4uiv),
+    SYM(MultiTexCoordP1ui),
+    SYM(MultiTexCoordP1uiv),
+    SYM(MultiTexCoordP2ui),
+    SYM(MultiTexCoordP2uiv),
+    SYM(MultiTexCoordP3ui),
+    SYM(MultiTexCoordP3uiv),
+    SYM(MultiTexCoordP4ui),
+    SYM(MultiTexCoordP4uiv),
+    SYM(NormalP3ui),
+    SYM(NormalP3uiv),
+    SYM(ColorP3ui),
+    SYM(ColorP3uiv),
+    SYM(ColorP4ui),
+    SYM(ColorP4uiv),
+    SYM(SecondaryColorP3ui),
+    SYM(SecondaryColorP3uiv),
+    SYM(MinSampleShading),
+    SYM(BlendEquationi),
+    SYM(BlendEquationSeparatei),
+    SYM(BlendFunci),
+    SYM(BlendFuncSeparatei),
+    SYM(DrawArraysIndirect),
+    SYM(DrawElementsIndirect),
+    SYM(Uniform1d),
+    SYM(Uniform2d),
+    SYM(Uniform3d),
+    SYM(Uniform4d),
+    SYM(Uniform1dv),
+    SYM(Uniform2dv),
+    SYM(Uniform3dv),
+    SYM(Uniform4dv),
+    SYM(UniformMatrix2dv),
+    SYM(UniformMatrix3dv),
+    SYM(UniformMatrix4dv),
+    SYM(UniformMatrix2x3dv),
+    SYM(UniformMatrix2x4dv),
+    SYM(UniformMatrix3x2dv),
+    SYM(UniformMatrix3x4dv),
+    SYM(UniformMatrix4x2dv),
+    SYM(UniformMatrix4x3dv),
+    SYM(GetUniformdv),
+    SYM(GetSubroutineUniformLocation),
+    SYM(GetSubroutineIndex),
+    SYM(GetActiveSubroutineUniformiv),
+    SYM(GetActiveSubroutineUniformName),
+    SYM(GetActiveSubroutineName),
+    SYM(UniformSubroutinesuiv),
+    SYM(GetUniformSubroutineuiv),
+    SYM(GetProgramStageiv),
+    SYM(PatchParameteri),
+    SYM(PatchParameterfv),
+    SYM(BindTransformFeedback),
+    SYM(DeleteTransformFeedbacks),
+    SYM(GenTransformFeedbacks),
+    SYM(IsTransformFeedback),
+    SYM(PauseTransformFeedback),
+    SYM(ResumeTransformFeedback),
+    SYM(DrawTransformFeedback),
+    SYM(DrawTransformFeedbackStream),
+    SYM(BeginQueryIndexed),
+    SYM(EndQueryIndexed),
+    SYM(GetQueryIndexediv),
+    SYM(ReleaseShaderCompiler),
+    SYM(ShaderBinary),
+    SYM(GetShaderPrecisionFormat),
+    SYM(DepthRangef),
+    SYM(ClearDepthf),
+    SYM(GetProgramBinary),
+    SYM(ProgramBinary),
+    SYM(ProgramParameteri),
+    SYM(UseProgramStages),
+    SYM(ActiveShaderProgram),
+    SYM(CreateShaderProgramv),
+    SYM(BindProgramPipeline),
+    SYM(DeleteProgramPipelines),
+    SYM(GenProgramPipelines),
+    SYM(IsProgramPipeline),
+    SYM(GetProgramPipelineiv),
+    SYM(ProgramUniform1i),
+    SYM(ProgramUniform1iv),
+    SYM(ProgramUniform1f),
+    SYM(ProgramUniform1fv),
+    SYM(ProgramUniform1d),
+    SYM(ProgramUniform1dv),
+    SYM(ProgramUniform1ui),
+    SYM(ProgramUniform1uiv),
+    SYM(ProgramUniform2i),
+    SYM(ProgramUniform2iv),
+    SYM(ProgramUniform2f),
+    SYM(ProgramUniform2fv),
+    SYM(ProgramUniform2d),
+    SYM(ProgramUniform2dv),
+    SYM(ProgramUniform2ui),
+    SYM(ProgramUniform2uiv),
+    SYM(ProgramUniform3i),
+    SYM(ProgramUniform3iv),
+    SYM(ProgramUniform3f),
+    SYM(ProgramUniform3fv),
+    SYM(ProgramUniform3d),
+    SYM(ProgramUniform3dv),
+    SYM(ProgramUniform3ui),
+    SYM(ProgramUniform3uiv),
+    SYM(ProgramUniform4i),
+    SYM(ProgramUniform4iv),
+    SYM(ProgramUniform4f),
+    SYM(ProgramUniform4fv),
+    SYM(ProgramUniform4d),
+    SYM(ProgramUniform4dv),
+    SYM(ProgramUniform4ui),
+    SYM(ProgramUniform4uiv),
+    SYM(ProgramUniformMatrix2fv),
+    SYM(ProgramUniformMatrix3fv),
+    SYM(ProgramUniformMatrix4fv),
+    SYM(ProgramUniformMatrix2dv),
+    SYM(ProgramUniformMatrix3dv),
+    SYM(ProgramUniformMatrix4dv),
+    SYM(ProgramUniformMatrix2x3fv),
+    SYM(ProgramUniformMatrix3x2fv),
+    SYM(ProgramUniformMatrix2x4fv),
+    SYM(ProgramUniformMatrix4x2fv),
+    SYM(ProgramUniformMatrix3x4fv),
+    SYM(ProgramUniformMatrix4x3fv),
+    SYM(ProgramUniformMatrix2x3dv),
+    SYM(ProgramUniformMatrix3x2dv),
+    SYM(ProgramUniformMatrix2x4dv),
+    SYM(ProgramUniformMatrix4x2dv),
+    SYM(ProgramUniformMatrix3x4dv),
+    SYM(ProgramUniformMatrix4x3dv),
+    SYM(ValidateProgramPipeline),
+    SYM(GetProgramPipelineInfoLog),
+    SYM(VertexAttribL1d),
+    SYM(VertexAttribL2d),
+    SYM(VertexAttribL3d),
+    SYM(VertexAttribL4d),
+    SYM(VertexAttribL1dv),
+    SYM(VertexAttribL2dv),
+    SYM(VertexAttribL3dv),
+    SYM(VertexAttribL4dv),
+    SYM(VertexAttribLPointer),
+    SYM(GetVertexAttribLdv),
+    SYM(ViewportArrayv),
+    SYM(ViewportIndexedf),
+    SYM(ViewportIndexedfv),
+    SYM(ScissorArrayv),
+    SYM(ScissorIndexed),
+    SYM(ScissorIndexedv),
+    SYM(DepthRangeArrayv),
+    SYM(DepthRangeIndexed),
+    SYM(GetFloati_v),
+    SYM(GetDoublei_v),
+    SYM(DrawArraysInstancedBaseInstance),
+    SYM(DrawElementsInstancedBaseInstance),
+    SYM(DrawElementsInstancedBaseVertexBaseInstance),
+    SYM(GetInternalformativ),
+    SYM(GetActiveAtomicCounterBufferiv),
+    SYM(BindImageTexture),
+    SYM(MemoryBarrier),
+    SYM(TexStorage1D),
+    SYM(TexStorage2D),
+    SYM(TexStorage3D),
+    SYM(DrawTransformFeedbackInstanced),
+    SYM(DrawTransformFeedbackStreamInstanced),
+    SYM(ClearBufferData),
+    SYM(ClearBufferSubData),
+    SYM(DispatchCompute),
+    SYM(DispatchComputeIndirect),
+    SYM(CopyImageSubData),
+    SYM(FramebufferParameteri),
+    SYM(GetFramebufferParameteriv),
+    SYM(GetInternalformati64v),
+    SYM(InvalidateTexSubImage),
+    SYM(InvalidateTexImage),
+    SYM(InvalidateBufferSubData),
+    SYM(InvalidateBufferData),
+    SYM(InvalidateFramebuffer),
+    SYM(InvalidateSubFramebuffer),
+    SYM(MultiDrawArraysIndirect),
+    SYM(MultiDrawElementsIndirect),
+    SYM(GetProgramInterfaceiv),
+    SYM(GetProgramResourceIndex),
+    SYM(GetProgramResourceName),
+    SYM(GetProgramResourceiv),
+    SYM(GetProgramResourceLocation),
+    SYM(GetProgramResourceLocationIndex),
+    SYM(ShaderStorageBlockBinding),
+    SYM(TexBufferRange),
+    SYM(TexStorage2DMultisample),
+    SYM(TexStorage3DMultisample),
+    SYM(TextureView),
+    SYM(BindVertexBuffer),
+    SYM(VertexAttribFormat),
+    SYM(VertexAttribIFormat),
+    SYM(VertexAttribLFormat),
+    SYM(VertexAttribBinding),
+    SYM(VertexBindingDivisor),
+    SYM(DebugMessageControl),
+    SYM(DebugMessageInsert),
+    SYM(DebugMessageCallback),
+    SYM(GetDebugMessageLog),
+    SYM(PushDebugGroup),
+    SYM(PopDebugGroup),
+    SYM(ObjectLabel),
+    SYM(GetObjectLabel),
+    SYM(ObjectPtrLabel),
+    SYM(GetObjectPtrLabel),
+    SYM(BufferStorage),
+    SYM(ClearTexImage),
+    SYM(ClearTexSubImage),
+    SYM(BindBuffersBase),
+    SYM(BindBuffersRange),
+    SYM(BindTextures),
+    SYM(BindSamplers),
+    SYM(BindImageTextures),
+    SYM(BindVertexBuffers),
+    SYM(GetTextureHandleARB),
+    SYM(GetTextureSamplerHandleARB),
+    SYM(MakeTextureHandleResidentARB),
+    SYM(MakeTextureHandleNonResidentARB),
+    SYM(GetImageHandleARB),
+    SYM(MakeImageHandleResidentARB),
+    SYM(MakeImageHandleNonResidentARB),
+    SYM(UniformHandleui64ARB),
+    SYM(UniformHandleui64vARB),
+    SYM(ProgramUniformHandleui64ARB),
+    SYM(ProgramUniformHandleui64vARB),
+    SYM(IsTextureHandleResidentARB),
+    SYM(IsImageHandleResidentARB),
+    SYM(VertexAttribL1ui64ARB),
+    SYM(VertexAttribL1ui64vARB),
+    SYM(GetVertexAttribLui64vARB),
+    SYM(CreateSyncFromCLeventARB),
+    SYM(ClampColorARB),
+    SYM(DispatchComputeGroupSizeARB),
+    SYM(DebugMessageControlARB),
+    SYM(DebugMessageInsertARB),
+    SYM(DebugMessageCallbackARB),
+    SYM(GetDebugMessageLogARB),
+    SYM(DrawBuffersARB),
+    SYM(BlendEquationiARB),
+    SYM(BlendEquationSeparateiARB),
+    SYM(BlendFunciARB),
+    SYM(BlendFuncSeparateiARB),
+    SYM(DrawArraysInstancedARB),
+    SYM(DrawElementsInstancedARB),
+    SYM(ProgramStringARB),
+    SYM(BindProgramARB),
+    SYM(DeleteProgramsARB),
+    SYM(GenProgramsARB),
+    SYM(ProgramEnvParameter4dARB),
+    SYM(ProgramEnvParameter4dvARB),
+    SYM(ProgramEnvParameter4fARB),
+    SYM(ProgramEnvParameter4fvARB),
+    SYM(ProgramLocalParameter4dARB),
+    SYM(ProgramLocalParameter4dvARB),
+    SYM(ProgramLocalParameter4fARB),
+    SYM(ProgramLocalParameter4fvARB),
+    SYM(GetProgramEnvParameterdvARB),
+    SYM(GetProgramEnvParameterfvARB),
+    SYM(GetProgramLocalParameterdvARB),
+    SYM(GetProgramLocalParameterfvARB),
+    SYM(GetProgramivARB),
+    SYM(GetProgramStringARB),
+    SYM(IsProgramARB),
+    SYM(ProgramParameteriARB),
+    SYM(FramebufferTextureARB),
+    SYM(FramebufferTextureLayerARB),
+    SYM(FramebufferTextureFaceARB),
+    SYM(ColorTable),
+    SYM(ColorTableParameterfv),
+    SYM(ColorTableParameteriv),
+    SYM(CopyColorTable),
+    SYM(GetColorTable),
+    SYM(GetColorTableParameterfv),
+    SYM(GetColorTableParameteriv),
+    SYM(ColorSubTable),
+    SYM(CopyColorSubTable),
+    SYM(ConvolutionFilter1D),
+    SYM(ConvolutionFilter2D),
+    SYM(ConvolutionParameterf),
+    SYM(ConvolutionParameterfv),
+    SYM(ConvolutionParameteri),
+    SYM(ConvolutionParameteriv),
+    SYM(CopyConvolutionFilter1D),
+    SYM(CopyConvolutionFilter2D),
+    SYM(GetConvolutionFilter),
+    SYM(GetConvolutionParameterfv),
+    SYM(GetConvolutionParameteriv),
+    SYM(GetSeparableFilter),
+    SYM(SeparableFilter2D),
+    SYM(GetHistogram),
+    SYM(GetHistogramParameterfv),
+    SYM(GetHistogramParameteriv),
+    SYM(GetMinmax),
+    SYM(GetMinmaxParameterfv),
+    SYM(GetMinmaxParameteriv),
+    SYM(Histogram),
+    SYM(Minmax),
+    SYM(ResetHistogram),
+    SYM(ResetMinmax),
+    SYM(MultiDrawArraysIndirectCountARB),
+    SYM(MultiDrawElementsIndirectCountARB),
+    SYM(VertexAttribDivisorARB),
+    SYM(CurrentPaletteMatrixARB),
+    SYM(MatrixIndexubvARB),
+    SYM(MatrixIndexusvARB),
+    SYM(MatrixIndexuivARB),
+    SYM(MatrixIndexPointerARB),
+    SYM(SampleCoverageARB),
+    SYM(ActiveTextureARB),
+    SYM(ClientActiveTextureARB),
+    SYM(MultiTexCoord1dARB),
+    SYM(MultiTexCoord1dvARB),
+    SYM(MultiTexCoord1fARB),
+    SYM(MultiTexCoord1fvARB),
+    SYM(MultiTexCoord1iARB),
+    SYM(MultiTexCoord1ivARB),
+    SYM(MultiTexCoord1sARB),
+    SYM(MultiTexCoord1svARB),
+    SYM(MultiTexCoord2dARB),
+    SYM(MultiTexCoord2dvARB),
+    SYM(MultiTexCoord2fARB),
+    SYM(MultiTexCoord2fvARB),
+    SYM(MultiTexCoord2iARB),
+    SYM(MultiTexCoord2ivARB),
+    SYM(MultiTexCoord2sARB),
+    SYM(MultiTexCoord2svARB),
+    SYM(MultiTexCoord3dARB),
+    SYM(MultiTexCoord3dvARB),
+    SYM(MultiTexCoord3fARB),
+    SYM(MultiTexCoord3fvARB),
+    SYM(MultiTexCoord3iARB),
+    SYM(MultiTexCoord3ivARB),
+    SYM(MultiTexCoord3sARB),
+    SYM(MultiTexCoord3svARB),
+    SYM(MultiTexCoord4dARB),
+    SYM(MultiTexCoord4dvARB),
+    SYM(MultiTexCoord4fARB),
+    SYM(MultiTexCoord4fvARB),
+    SYM(MultiTexCoord4iARB),
+    SYM(MultiTexCoord4ivARB),
+    SYM(MultiTexCoord4sARB),
+    SYM(MultiTexCoord4svARB),
+    SYM(GenQueriesARB),
+    SYM(DeleteQueriesARB),
+    SYM(IsQueryARB),
+    SYM(BeginQueryARB),
+    SYM(EndQueryARB),
+    SYM(GetQueryivARB),
+    SYM(GetQueryObjectivARB),
+    SYM(GetQueryObjectuivARB),
+    SYM(PointParameterfARB),
+    SYM(PointParameterfvARB),
+    SYM(GetGraphicsResetStatusARB),
+    SYM(GetnTexImageARB),
+    SYM(ReadnPixelsARB),
+    SYM(GetnCompressedTexImageARB),
+    SYM(GetnUniformfvARB),
+    SYM(GetnUniformivARB),
+    SYM(GetnUniformuivARB),
+    SYM(GetnUniformdvARB),
+    SYM(GetnMapdvARB),
+    SYM(GetnMapfvARB),
+    SYM(GetnMapivARB),
+    SYM(GetnPixelMapfvARB),
+    SYM(GetnPixelMapuivARB),
+    SYM(GetnPixelMapusvARB),
+    SYM(GetnPolygonStippleARB),
+    SYM(GetnColorTableARB),
+    SYM(GetnConvolutionFilterARB),
+    SYM(GetnSeparableFilterARB),
+    SYM(GetnHistogramARB),
+    SYM(GetnMinmaxARB),
+    SYM(MinSampleShadingARB),
+    SYM(DeleteObjectARB),
+    SYM(GetHandleARB),
+    SYM(DetachObjectARB),
+    SYM(CreateShaderObjectARB),
+    SYM(ShaderSourceARB),
+    SYM(CompileShaderARB),
+    SYM(CreateProgramObjectARB),
+    SYM(AttachObjectARB),
+    SYM(LinkProgramARB),
+    SYM(UseProgramObjectARB),
+    SYM(ValidateProgramARB),
+    SYM(Uniform1fARB),
+    SYM(Uniform2fARB),
+    SYM(Uniform3fARB),
+    SYM(Uniform4fARB),
+    SYM(Uniform1iARB),
+    SYM(Uniform2iARB),
+    SYM(Uniform3iARB),
+    SYM(Uniform4iARB),
+    SYM(Uniform1fvARB),
+    SYM(Uniform2fvARB),
+    SYM(Uniform3fvARB),
+    SYM(Uniform4fvARB),
+    SYM(Uniform1ivARB),
+    SYM(Uniform2ivARB),
+    SYM(Uniform3ivARB),
+    SYM(Uniform4ivARB),
+    SYM(UniformMatrix2fvARB),
+    SYM(UniformMatrix3fvARB),
+    SYM(UniformMatrix4fvARB),
+    SYM(GetObjectParameterfvARB),
+    SYM(GetObjectParameterivARB),
+    SYM(GetInfoLogARB),
+    SYM(GetAttachedObjectsARB),
+    SYM(GetUniformLocationARB),
+    SYM(GetActiveUniformARB),
+    SYM(GetUniformfvARB),
+    SYM(GetUniformivARB),
+    SYM(GetShaderSourceARB),
+    SYM(NamedStringARB),
+    SYM(DeleteNamedStringARB),
+    SYM(CompileShaderIncludeARB),
+    SYM(IsNamedStringARB),
+    SYM(GetNamedStringARB),
+    SYM(GetNamedStringivARB),
+    SYM(TexPageCommitmentARB),
+    SYM(TexBufferARB),
+    SYM(CompressedTexImage3DARB),
+    SYM(CompressedTexImage2DARB),
+    SYM(CompressedTexImage1DARB),
+    SYM(CompressedTexSubImage3DARB),
+    SYM(CompressedTexSubImage2DARB),
+    SYM(CompressedTexSubImage1DARB),
+    SYM(GetCompressedTexImageARB),
+    SYM(LoadTransposeMatrixfARB),
+    SYM(LoadTransposeMatrixdARB),
+    SYM(MultTransposeMatrixfARB),
+    SYM(MultTransposeMatrixdARB),
+    SYM(WeightbvARB),
+    SYM(WeightsvARB),
+    SYM(WeightivARB),
+    SYM(WeightfvARB),
+    SYM(WeightdvARB),
+    SYM(WeightubvARB),
+    SYM(WeightusvARB),
+    SYM(WeightuivARB),
+    SYM(WeightPointerARB),
+    SYM(VertexBlendARB),
+    SYM(BindBufferARB),
+    SYM(DeleteBuffersARB),
+    SYM(GenBuffersARB),
+    SYM(IsBufferARB),
+    SYM(BufferDataARB),
+    SYM(BufferSubDataARB),
+    SYM(GetBufferSubDataARB),
+    SYM(MapBufferARB),
+    SYM(UnmapBufferARB),
+    SYM(GetBufferParameterivARB),
+    SYM(GetBufferPointervARB),
+    SYM(VertexAttrib1dARB),
+    SYM(VertexAttrib1dvARB),
+    SYM(VertexAttrib1fARB),
+    SYM(VertexAttrib1fvARB),
+    SYM(VertexAttrib1sARB),
+    SYM(VertexAttrib1svARB),
+    SYM(VertexAttrib2dARB),
+    SYM(VertexAttrib2dvARB),
+    SYM(VertexAttrib2fARB),
+    SYM(VertexAttrib2fvARB),
+    SYM(VertexAttrib2sARB),
+    SYM(VertexAttrib2svARB),
+    SYM(VertexAttrib3dARB),
+    SYM(VertexAttrib3dvARB),
+    SYM(VertexAttrib3fARB),
+    SYM(VertexAttrib3fvARB),
+    SYM(VertexAttrib3sARB),
+    SYM(VertexAttrib3svARB),
+    SYM(VertexAttrib4NbvARB),
+    SYM(VertexAttrib4NivARB),
+    SYM(VertexAttrib4NsvARB),
+    SYM(VertexAttrib4NubARB),
+    SYM(VertexAttrib4NubvARB),
+    SYM(VertexAttrib4NuivARB),
+    SYM(VertexAttrib4NusvARB),
+    SYM(VertexAttrib4bvARB),
+    SYM(VertexAttrib4dARB),
+    SYM(VertexAttrib4dvARB),
+    SYM(VertexAttrib4fARB),
+    SYM(VertexAttrib4fvARB),
+    SYM(VertexAttrib4ivARB),
+    SYM(VertexAttrib4sARB),
+    SYM(VertexAttrib4svARB),
+    SYM(VertexAttrib4ubvARB),
+    SYM(VertexAttrib4uivARB),
+    SYM(VertexAttrib4usvARB),
+    SYM(VertexAttribPointerARB),
+    SYM(EnableVertexAttribArrayARB),
+    SYM(DisableVertexAttribArrayARB),
+    SYM(GetVertexAttribdvARB),
+    SYM(GetVertexAttribfvARB),
+    SYM(GetVertexAttribivARB),
+    SYM(GetVertexAttribPointervARB),
+    SYM(BindAttribLocationARB),
+    SYM(GetActiveAttribARB),
+    SYM(GetAttribLocationARB),
+    SYM(WindowPos2dARB),
+    SYM(WindowPos2dvARB),
+    SYM(WindowPos2fARB),
+    SYM(WindowPos2fvARB),
+    SYM(WindowPos2iARB),
+    SYM(WindowPos2ivARB),
+    SYM(WindowPos2sARB),
+    SYM(WindowPos2svARB),
+    SYM(WindowPos3dARB),
+    SYM(WindowPos3dvARB),
+    SYM(WindowPos3fARB),
+    SYM(WindowPos3fvARB),
+    SYM(WindowPos3iARB),
+    SYM(WindowPos3ivARB),
+    SYM(WindowPos3sARB),
+    SYM(WindowPos3svARB),
+    SYM(MultiTexCoord1bOES),
+    SYM(MultiTexCoord1bvOES),
+    SYM(MultiTexCoord2bOES),
+    SYM(MultiTexCoord2bvOES),
+    SYM(MultiTexCoord3bOES),
+    SYM(MultiTexCoord3bvOES),
+    SYM(MultiTexCoord4bOES),
+    SYM(MultiTexCoord4bvOES),
+    SYM(TexCoord1bOES),
+    SYM(TexCoord1bvOES),
+    SYM(TexCoord2bOES),
+    SYM(TexCoord2bvOES),
+    SYM(TexCoord3bOES),
+    SYM(TexCoord3bvOES),
+    SYM(TexCoord4bOES),
+    SYM(TexCoord4bvOES),
+    SYM(Vertex2bOES),
+    SYM(Vertex2bvOES),
+    SYM(Vertex3bOES),
+    SYM(Vertex3bvOES),
+    SYM(Vertex4bOES),
+    SYM(Vertex4bvOES),
+    SYM(AlphaFuncxOES),
+    SYM(ClearColorxOES),
+    SYM(ClearDepthxOES),
+    SYM(ClipPlanexOES),
+    SYM(Color4xOES),
+    SYM(DepthRangexOES),
+    SYM(FogxOES),
+    SYM(FogxvOES),
+    SYM(FrustumxOES),
+    SYM(GetClipPlanexOES),
+    SYM(GetFixedvOES),
+    SYM(GetTexEnvxvOES),
+    SYM(GetTexParameterxvOES),
+    SYM(LightModelxOES),
+    SYM(LightModelxvOES),
+    SYM(LightxOES),
+    SYM(LightxvOES),
+    SYM(LineWidthxOES),
+    SYM(LoadMatrixxOES),
+    SYM(MaterialxOES),
+    SYM(MaterialxvOES),
+    SYM(MultMatrixxOES),
+    SYM(MultiTexCoord4xOES),
+    SYM(Normal3xOES),
+    SYM(OrthoxOES),
+    SYM(PointParameterxvOES),
+    SYM(PointSizexOES),
+    SYM(PolygonOffsetxOES),
+    SYM(RotatexOES),
+    SYM(SampleCoverageOES),
+    SYM(ScalexOES),
+    SYM(TexEnvxOES),
+    SYM(TexEnvxvOES),
+    SYM(TexParameterxOES),
+    SYM(TexParameterxvOES),
+    SYM(TranslatexOES),
+    SYM(AccumxOES),
+    SYM(BitmapxOES),
+    SYM(BlendColorxOES),
+    SYM(ClearAccumxOES),
+    SYM(Color3xOES),
+    SYM(Color3xvOES),
+    SYM(Color4xvOES),
+    SYM(ConvolutionParameterxOES),
+    SYM(ConvolutionParameterxvOES),
+    SYM(EvalCoord1xOES),
+    SYM(EvalCoord1xvOES),
+    SYM(EvalCoord2xOES),
+    SYM(EvalCoord2xvOES),
+    SYM(FeedbackBufferxOES),
+    SYM(GetConvolutionParameterxvOES),
+    SYM(GetHistogramParameterxvOES),
+    SYM(GetLightxOES),
+    SYM(GetMapxvOES),
+    SYM(GetMaterialxOES),
+    SYM(GetPixelMapxv),
+    SYM(GetTexGenxvOES),
+    SYM(GetTexLevelParameterxvOES),
+    SYM(IndexxOES),
+    SYM(IndexxvOES),
+    SYM(LoadTransposeMatrixxOES),
+    SYM(Map1xOES),
+    SYM(Map2xOES),
+    SYM(MapGrid1xOES),
+    SYM(MapGrid2xOES),
+    SYM(MultTransposeMatrixxOES),
+    SYM(MultiTexCoord1xOES),
+    SYM(MultiTexCoord1xvOES),
+    SYM(MultiTexCoord2xOES),
+    SYM(MultiTexCoord2xvOES),
+    SYM(MultiTexCoord3xOES),
+    SYM(MultiTexCoord3xvOES),
+    SYM(MultiTexCoord4xvOES),
+    SYM(Normal3xvOES),
+    SYM(PassThroughxOES),
+    SYM(PixelMapx),
+    SYM(PixelStorex),
+    SYM(PixelTransferxOES),
+    SYM(PixelZoomxOES),
+    SYM(PrioritizeTexturesxOES),
+    SYM(RasterPos2xOES),
+    SYM(RasterPos2xvOES),
+    SYM(RasterPos3xOES),
+    SYM(RasterPos3xvOES),
+    SYM(RasterPos4xOES),
+    SYM(RasterPos4xvOES),
+    SYM(RectxOES),
+    SYM(RectxvOES),
+    SYM(TexCoord1xOES),
+    SYM(TexCoord1xvOES),
+    SYM(TexCoord2xOES),
+    SYM(TexCoord2xvOES),
+    SYM(TexCoord3xOES),
+    SYM(TexCoord3xvOES),
+    SYM(TexCoord4xOES),
+    SYM(TexCoord4xvOES),
+    SYM(TexGenxOES),
+    SYM(TexGenxvOES),
+    SYM(Vertex2xOES),
+    SYM(Vertex2xvOES),
+    SYM(Vertex3xOES),
+    SYM(Vertex3xvOES),
+    SYM(Vertex4xOES),
+    SYM(Vertex4xvOES),
+    SYM(QueryMatrixxOES),
+    SYM(ClearDepthfOES),
+    SYM(ClipPlanefOES),
+    SYM(DepthRangefOES),
+    SYM(FrustumfOES),
+    SYM(GetClipPlanefOES),
+    SYM(OrthofOES),
+    SYM(ImageTransformParameteriHP),
+    SYM(ImageTransformParameterfHP),
+    SYM(ImageTransformParameterivHP),
+    SYM(ImageTransformParameterfvHP),
+    SYM(GetImageTransformParameterivHP),
+    SYM(GetImageTransformParameterfvHP),
+
+    { NULL, NULL },
+};
+RGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;
+RGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;
+RGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;
+RGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;
+RGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;
+RGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;
+RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;
+RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;
+RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;
+RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;
+RGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;
+RGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;
+RGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;
+RGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;
+RGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;
+RGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;
+RGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;
+RGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;
+RGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;
+RGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;
+RGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;
+RGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;
+RGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;
+RGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;
+RGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;
+RGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;
+RGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;
+RGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;
+RGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;
+RGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;
+RGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;
+RGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;
+RGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;
+RGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;
+RGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;
+RGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;
+RGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;
+RGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;
+RGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;
+RGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;
+RGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;
+RGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;
+RGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;
+RGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;
+RGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;
+RGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;
+RGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;
+RGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;
+RGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;
+RGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;
+RGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;
+RGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;
+RGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;
+RGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;
+RGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;
+RGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;
+RGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;
+RGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;
+RGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;
+RGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;
+RGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;
+RGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;
+RGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;
+RGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;
+RGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;
+RGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;
+RGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;
+RGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;
+RGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;
+RGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;
+RGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;
+RGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;
+RGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;
+RGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;
+RGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;
+RGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;
+RGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;
+RGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;
+RGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;
+RGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;
+RGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;
+RGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;
+RGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;
+RGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;
+RGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;
+RGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;
+RGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;
+RGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;
+RGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;
+RGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;
+RGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;
+RGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;
+RGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;
+RGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;
+RGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;
+RGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;
+RGLSYMGLISQUERYPROC __rglgen_glIsQuery;
+RGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;
+RGLSYMGLENDQUERYPROC __rglgen_glEndQuery;
+RGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;
+RGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;
+RGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;
+RGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;
+RGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;
+RGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;
+RGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;
+RGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;
+RGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;
+RGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;
+RGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;
+RGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;
+RGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;
+RGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;
+RGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;
+RGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;
+RGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;
+RGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;
+RGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;
+RGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;
+RGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;
+RGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;
+RGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;
+RGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;
+RGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;
+RGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;
+RGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;
+RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;
+RGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;
+RGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;
+RGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;
+RGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;
+RGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;
+RGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;
+RGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;
+RGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;
+RGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;
+RGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;
+RGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;
+RGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;
+RGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;
+RGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;
+RGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;
+RGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;
+RGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;
+RGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;
+RGLSYMGLISSHADERPROC __rglgen_glIsShader;
+RGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;
+RGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;
+RGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;
+RGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;
+RGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;
+RGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;
+RGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;
+RGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;
+RGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;
+RGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;
+RGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;
+RGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;
+RGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;
+RGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;
+RGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;
+RGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;
+RGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;
+RGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;
+RGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;
+RGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;
+RGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;
+RGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;
+RGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;
+RGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;
+RGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;
+RGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;
+RGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;
+RGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;
+RGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;
+RGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;
+RGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;
+RGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;
+RGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;
+RGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;
+RGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;
+RGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;
+RGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;
+RGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;
+RGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;
+RGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;
+RGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;
+RGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;
+RGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;
+RGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;
+RGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;
+RGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;
+RGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;
+RGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;
+RGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;
+RGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;
+RGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;
+RGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;
+RGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;
+RGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;
+RGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;
+RGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;
+RGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;
+RGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;
+RGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;
+RGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;
+RGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;
+RGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;
+RGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;
+RGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;
+RGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;
+RGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;
+RGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;
+RGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;
+RGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;
+RGLSYMGLENABLEIPROC __rglgen_glEnablei;
+RGLSYMGLDISABLEIPROC __rglgen_glDisablei;
+RGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;
+RGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;
+RGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;
+RGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;
+RGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;
+RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;
+RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;
+RGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;
+RGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;
+RGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;
+RGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;
+RGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;
+RGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;
+RGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;
+RGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;
+RGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;
+RGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;
+RGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;
+RGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;
+RGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;
+RGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;
+RGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;
+RGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;
+RGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;
+RGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;
+RGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;
+RGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;
+RGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;
+RGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;
+RGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;
+RGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;
+RGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;
+RGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;
+RGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;
+RGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;
+RGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;
+RGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;
+RGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;
+RGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;
+RGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;
+RGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;
+RGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;
+RGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;
+RGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;
+RGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;
+RGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;
+RGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;
+RGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;
+RGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;
+RGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;
+RGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;
+RGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;
+RGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;
+RGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;
+RGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;
+RGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;
+RGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;
+RGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;
+RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;
+RGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;
+RGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;
+RGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;
+RGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;
+RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;
+RGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;
+RGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;
+RGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;
+RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;
+RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;
+RGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;
+RGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;
+RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;
+RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;
+RGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;
+RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;
+RGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;
+RGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;
+RGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;
+RGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;
+RGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;
+RGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;
+RGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;
+RGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;
+RGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;
+RGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;
+RGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;
+RGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;
+RGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;
+RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;
+RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;
+RGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;
+RGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;
+RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;
+RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;
+RGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;
+RGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;
+RGLSYMGLISSYNCPROC __rglgen_glIsSync;
+RGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;
+RGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;
+RGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;
+RGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;
+RGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;
+RGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;
+RGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;
+RGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;
+RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;
+RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;
+RGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;
+RGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;
+RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;
+RGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;
+RGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;
+RGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;
+RGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;
+RGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;
+RGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;
+RGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;
+RGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;
+RGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;
+RGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;
+RGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;
+RGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;
+RGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;
+RGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;
+RGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;
+RGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;
+RGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;
+RGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;
+RGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;
+RGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;
+RGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;
+RGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;
+RGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;
+RGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;
+RGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;
+RGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;
+RGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;
+RGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;
+RGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;
+RGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;
+RGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;
+RGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;
+RGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;
+RGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;
+RGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;
+RGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;
+RGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;
+RGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;
+RGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;
+RGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;
+RGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;
+RGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;
+RGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;
+RGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;
+RGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;
+RGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;
+RGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;
+RGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;
+RGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;
+RGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;
+RGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;
+RGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;
+RGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;
+RGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;
+RGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;
+RGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;
+RGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;
+RGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;
+RGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;
+RGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;
+RGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;
+RGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;
+RGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;
+RGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;
+RGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;
+RGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;
+RGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;
+RGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;
+RGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;
+RGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;
+RGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;
+RGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;
+RGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;
+RGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;
+RGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;
+RGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;
+RGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;
+RGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;
+RGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;
+RGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;
+RGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;
+RGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;
+RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;
+RGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;
+RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;
+RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;
+RGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;
+RGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;
+RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;
+RGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;
+RGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;
+RGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;
+RGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;
+RGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;
+RGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;
+RGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;
+RGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;
+RGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;
+RGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;
+RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;
+RGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;
+RGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;
+RGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;
+RGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;
+RGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;
+RGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;
+RGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;
+RGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;
+RGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;
+RGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;
+RGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;
+RGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;
+RGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;
+RGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;
+RGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;
+RGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;
+RGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;
+RGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;
+RGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;
+RGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;
+RGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;
+RGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;
+RGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;
+RGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;
+RGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;
+RGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;
+RGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;
+RGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;
+RGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;
+RGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;
+RGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;
+RGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;
+RGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;
+RGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;
+RGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;
+RGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;
+RGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;
+RGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;
+RGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;
+RGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;
+RGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;
+RGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;
+RGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;
+RGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;
+RGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;
+RGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;
+RGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;
+RGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;
+RGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;
+RGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;
+RGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;
+RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;
+RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;
+RGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;
+RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;
+RGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;
+RGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;
+RGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;
+RGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;
+RGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;
+RGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;
+RGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;
+RGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;
+RGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;
+RGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;
+RGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;
+RGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;
+RGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;
+RGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;
+RGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;
+RGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;
+RGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;
+RGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;
+RGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;
+RGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;
+RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;
+RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;
+RGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;
+RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;
+RGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;
+RGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;
+RGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;
+RGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;
+RGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;
+RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;
+RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;
+RGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;
+RGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;
+RGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;
+RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;
+RGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;
+RGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;
+RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;
+RGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;
+RGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;
+RGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;
+RGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;
+RGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;
+RGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;
+RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;
+RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;
+RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;
+RGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;
+RGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;
+RGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;
+RGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;
+RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;
+RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;
+RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;
+RGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;
+RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;
+RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;
+RGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;
+RGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;
+RGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;
+RGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;
+RGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;
+RGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;
+RGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;
+RGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;
+RGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;
+RGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;
+RGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;
+RGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;
+RGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;
+RGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;
+RGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;
+RGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;
+RGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;
+RGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;
+RGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;
+RGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;
+RGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;
+RGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;
+RGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;
+RGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;
+RGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;
+RGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;
+RGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;
+RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;
+RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;
+RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;
+RGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;
+RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;
+RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;
+RGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;
+RGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;
+RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;
+RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;
+RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;
+RGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;
+RGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;
+RGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;
+RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;
+RGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;
+RGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;
+RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;
+RGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;
+RGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;
+RGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;
+RGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;
+RGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;
+RGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;
+RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;
+RGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;
+RGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;
+RGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;
+RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;
+RGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;
+RGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;
+RGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;
+RGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;
+RGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;
+RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;
+RGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;
+RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;
+RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;
+RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;
+RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;
+RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;
+RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;
+RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;
+RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;
+RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;
+RGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;
+RGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;
+RGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;
+RGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;
+RGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;
+RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;
+RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;
+RGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;
+RGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;
+RGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;
+RGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;
+RGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;
+RGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;
+RGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;
+RGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;
+RGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;
+RGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;
+RGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;
+RGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;
+RGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;
+RGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;
+RGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;
+RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;
+RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;
+RGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;
+RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;
+RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;
+RGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;
+RGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;
+RGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;
+RGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;
+RGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;
+RGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;
+RGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;
+RGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;
+RGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;
+RGLSYMGLMINMAXPROC __rglgen_glMinmax;
+RGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;
+RGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;
+RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;
+RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;
+RGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;
+RGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;
+RGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;
+RGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;
+RGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;
+RGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;
+RGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;
+RGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;
+RGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;
+RGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;
+RGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;
+RGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;
+RGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;
+RGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;
+RGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;
+RGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;
+RGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;
+RGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;
+RGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;
+RGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;
+RGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;
+RGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;
+RGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;
+RGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;
+RGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;
+RGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;
+RGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;
+RGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;
+RGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;
+RGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;
+RGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;
+RGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;
+RGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;
+RGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;
+RGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;
+RGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;
+RGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;
+RGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;
+RGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;
+RGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;
+RGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;
+RGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;
+RGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;
+RGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;
+RGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;
+RGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;
+RGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;
+RGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;
+RGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;
+RGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;
+RGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;
+RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;
+RGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;
+RGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;
+RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;
+RGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;
+RGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;
+RGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;
+RGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;
+RGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;
+RGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;
+RGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;
+RGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;
+RGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;
+RGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;
+RGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;
+RGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;
+RGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;
+RGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;
+RGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;
+RGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;
+RGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;
+RGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;
+RGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;
+RGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;
+RGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;
+RGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;
+RGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;
+RGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;
+RGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;
+RGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;
+RGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;
+RGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;
+RGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;
+RGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;
+RGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;
+RGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;
+RGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;
+RGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;
+RGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;
+RGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;
+RGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;
+RGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;
+RGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;
+RGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;
+RGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;
+RGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;
+RGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;
+RGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;
+RGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;
+RGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;
+RGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;
+RGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;
+RGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;
+RGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;
+RGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;
+RGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;
+RGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;
+RGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;
+RGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;
+RGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;
+RGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;
+RGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;
+RGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;
+RGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;
+RGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;
+RGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;
+RGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;
+RGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;
+RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;
+RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;
+RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;
+RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;
+RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;
+RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;
+RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;
+RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;
+RGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;
+RGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;
+RGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;
+RGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;
+RGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;
+RGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;
+RGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;
+RGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;
+RGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;
+RGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;
+RGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;
+RGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;
+RGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;
+RGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;
+RGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;
+RGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;
+RGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;
+RGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;
+RGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;
+RGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;
+RGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;
+RGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;
+RGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;
+RGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;
+RGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;
+RGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;
+RGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;
+RGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;
+RGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;
+RGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;
+RGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;
+RGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;
+RGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;
+RGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;
+RGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;
+RGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;
+RGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;
+RGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;
+RGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;
+RGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;
+RGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;
+RGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;
+RGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;
+RGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;
+RGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;
+RGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;
+RGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;
+RGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;
+RGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;
+RGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;
+RGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;
+RGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;
+RGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;
+RGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;
+RGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;
+RGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;
+RGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;
+RGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;
+RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;
+RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;
+RGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;
+RGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;
+RGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;
+RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;
+RGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;
+RGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;
+RGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;
+RGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;
+RGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;
+RGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;
+RGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;
+RGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;
+RGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;
+RGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;
+RGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;
+RGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;
+RGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;
+RGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;
+RGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;
+RGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;
+RGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;
+RGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;
+RGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;
+RGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;
+RGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;
+RGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;
+RGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;
+RGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;
+RGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;
+RGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;
+RGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;
+RGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;
+RGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;
+RGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;
+RGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;
+RGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;
+RGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;
+RGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;
+RGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;
+RGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;
+RGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;
+RGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;
+RGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;
+RGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;
+RGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;
+RGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;
+RGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;
+RGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;
+RGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;
+RGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;
+RGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;
+RGLSYMGLFOGXOESPROC __rglgen_glFogxOES;
+RGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;
+RGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;
+RGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;
+RGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;
+RGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;
+RGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;
+RGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;
+RGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;
+RGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;
+RGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;
+RGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;
+RGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;
+RGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;
+RGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;
+RGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;
+RGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;
+RGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;
+RGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;
+RGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;
+RGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;
+RGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;
+RGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;
+RGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;
+RGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;
+RGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;
+RGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;
+RGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;
+RGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;
+RGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;
+RGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;
+RGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;
+RGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;
+RGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;
+RGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;
+RGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;
+RGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;
+RGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;
+RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;
+RGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;
+RGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;
+RGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;
+RGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;
+RGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;
+RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;
+RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;
+RGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;
+RGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;
+RGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;
+RGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;
+RGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;
+RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;
+RGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;
+RGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;
+RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;
+RGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;
+RGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;
+RGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;
+RGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;
+RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;
+RGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;
+RGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;
+RGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;
+RGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;
+RGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;
+RGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;
+RGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;
+RGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;
+RGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;
+RGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;
+RGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;
+RGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;
+RGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;
+RGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;
+RGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;
+RGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;
+RGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;
+RGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;
+RGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;
+RGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;
+RGLSYMGLRECTXOESPROC __rglgen_glRectxOES;
+RGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;
+RGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;
+RGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;
+RGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;
+RGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;
+RGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;
+RGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;
+RGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;
+RGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;
+RGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;
+RGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;
+RGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;
+RGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;
+RGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;
+RGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;
+RGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;
+RGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;
+RGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;
+RGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;
+RGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;
+RGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;
+RGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;
+RGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;
+RGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;
+RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;
+RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;
+RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;
+RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;
+RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;
+RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;
diff --git a/deps/libretro-common/glsym/rglgen.c b/deps/libretro-common/glsym/rglgen.c
new file mode 100644 (file)
index 0000000..d1c4119
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsym).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <string.h>
+
+#include <glsym/rglgen.h>
+#include <glsym/glsym.h>
+
+void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
+      const struct rglgen_sym_map *map)
+{
+   for (; map->sym; map++)
+   {
+      rglgen_func_t func = proc(map->sym);
+      memcpy(map->ptr, &func, sizeof(func));
+   }
+}
+
+void rglgen_resolve_symbols(rglgen_proc_address_t proc)
+{
+   if (!proc)
+      return;
+
+   rglgen_resolve_symbols_custom(proc, rglgen_symbol_map);
+}
diff --git a/deps/libretro-common/glsym/rglgen.py b/deps/libretro-common/glsym/rglgen.py
new file mode 100755 (executable)
index 0000000..ee43be2
--- /dev/null
@@ -0,0 +1,147 @@
+#!/usr/bin/env python3
+
+"""
+   License statement applies to this file (glgen.py) only.
+
+   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.
+"""
+
+import sys
+import os
+import re
+
+banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]
+
+def noext(sym):
+   for ext in banned_ext:
+      if sym.endswith(ext):
+         return False
+   return True
+
+def fix_multiline_functions(lines):
+   fixed_lines = []
+   temp_lines = []
+   for line in lines:
+      if line.count('(') > line.count(')'):
+         temp_lines.append(line)
+      else:
+         if len(temp_lines) > 0:
+            if line.count(')') > line.count('('):
+               temp_lines.append(line)
+               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
+               fixed_lines.append(fixed_line)
+               temp_lines = []
+            else:
+               temp_lines.append(line)
+         else:
+            fixed_lines.append(line)
+   return fixed_lines
+
+def find_gl_symbols(lines):
+   typedefs = []
+   syms = []
+   for line in lines:
+      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
+      g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
+      if m and noext(m.group(1)):
+         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
+      if g and noext(g.group(1)):
+         syms.append(g.group(1))
+   return (typedefs, syms)
+
+def generate_defines(gl_syms):
+   res = []
+   for line in gl_syms:
+      res.append('#define {} __rglgen_{}'.format(line, line))
+   return res
+
+def generate_declarations(gl_syms):
+   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]
+
+def generate_macros(gl_syms):
+   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]
+
+def dump(f, lines):
+   f.write('\n'.join(lines))
+   f.write('\n\n')
+
+if __name__ == '__main__':
+
+   if len(sys.argv) > 4:
+      for banned in sys.argv[4:]:
+         banned_ext.append(banned)
+
+   with open(sys.argv[1], 'r') as f:
+      lines = fix_multiline_functions(f.readlines())
+      typedefs, syms = find_gl_symbols(lines)
+
+      overrides = generate_defines(syms)
+      declarations = generate_declarations(syms)
+      externs = ['extern ' + x for x in declarations]
+
+      macros = generate_macros(syms)
+
+   with open(sys.argv[2], 'w') as f:
+      f.write('#ifndef RGLGEN_DECL_H__\n')
+      f.write('#define RGLGEN_DECL_H__\n')
+
+      f.write('#ifdef __cplusplus\n')
+      f.write('extern "C" {\n')
+      f.write('#endif\n')
+
+      f.write('#ifdef GL_APIENTRY\n')
+      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('#else\n')
+      f.write('#ifndef APIENTRY\n')
+      f.write('#define APIENTRY\n')
+      f.write('#endif\n')
+      f.write('#ifndef APIENTRYP\n')
+      f.write('#define APIENTRYP APIENTRY *\n')
+      f.write('#endif\n')
+      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('#endif\n')
+
+      f.write('#ifndef GL_OES_EGL_image\n')
+      f.write('typedef void *GLeglImageOES;\n')
+      f.write('#endif\n')
+
+      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
+      f.write('typedef GLint GLfixed;\n')
+      f.write('#endif\n')
+
+      dump(f, typedefs)
+      dump(f, overrides)
+      dump(f, externs)
+
+      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
+      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')
+
+      f.write('#ifdef __cplusplus\n')
+      f.write('}\n')
+      f.write('#endif\n')
+
+      f.write('#endif\n')
+
+   with open(sys.argv[3], 'w') as f:
+      f.write('#include "glsym/glsym.h"\n')
+      f.write('#include <stddef.h>\n')
+      f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
+      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
+      dump(f, macros)
+      f.write('    { NULL, NULL },\n')
+      f.write('};\n')
+      dump(f, declarations)
diff --git a/deps/libretro-common/glsym/xglgen.py b/deps/libretro-common/glsym/xglgen.py
new file mode 100644 (file)
index 0000000..215ffff
--- /dev/null
@@ -0,0 +1,156 @@
+#!/usr/bin/env python3
+
+"""
+   License statement applies to this file (xglgen.py) only.
+
+   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.
+"""
+
+import sys
+import os
+import re
+
+banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]
+
+def noext(sym):
+   for ext in banned_ext:
+      if sym.endswith(ext):
+         return False
+   return True
+
+def fix_multiline_functions(lines):
+   fixed_lines = []
+   temp_lines = []
+   for line in lines:
+      if line.count('(') > line.count(')'):
+         temp_lines.append(line)
+      else:
+         if len(temp_lines) > 0:
+            if line.count(')') > line.count('('):
+               temp_lines.append(line)
+               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
+               fixed_lines.append(fixed_line)
+               temp_lines = []
+            else:
+               temp_lines.append(line)
+         else:
+            fixed_lines.append(line)
+   return fixed_lines
+
+def find_gl_symbols(lines):
+   typedefs = []
+   syms = []
+   for line in lines:
+      # Note this doesn't work automated; this script is designed as a helper
+      m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
+      g = re.search(r'^GLAPI\s(.+)\s(.+)\s(gl\S+)\W*\((.+)\).*', line)
+      if g and noext(g.group(3)):
+         typedefs.append('typedef ' + g.group(1) + ' (APIENTRYP RGLSYM' + g.group(3).upper() + 'PROC) (' + g.group(4) + ');')
+         syms.append(g.group(3))
+
+   return (typedefs, syms)
+
+def generate_defines(gl_syms):
+   res = []
+   for line in gl_syms:
+      res.append('#define {} __rglgen_{}'.format(line, line))
+   return res
+
+def generate_declarations(gl_syms):
+   return ['RGLSYM' + x.upper() + 'PROC ' + x + ';' for x in gl_syms]
+
+def generate_macros(gl_syms):
+   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]
+
+def dump(f, lines):
+   f.write('\n'.join(lines))
+   f.write('\n\n')
+
+if __name__ == '__main__':
+
+   if len(sys.argv) > 4:
+      for banned in sys.argv[4:]:
+         banned_ext.append(banned)
+
+   with open(sys.argv[1], 'r') as f:
+      lines = fix_multiline_functions(f.readlines())
+      typedefs, syms = find_gl_symbols(lines)
+
+      overrides = generate_defines(syms)
+      declarations = generate_declarations(syms)
+      externs = ['extern ' + x for x in declarations]
+
+      macros = generate_macros(syms)
+
+   with open(sys.argv[2], 'w') as f:
+      f.write('#ifndef RGLGEN_DECL_H__\n')
+      f.write('#define RGLGEN_DECL_H__\n')
+
+      f.write('#ifdef __cplusplus\n')
+      f.write('extern "C" {\n')
+      f.write('#endif\n')
+
+      f.write('#ifdef GL_APIENTRY\n')
+      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('#else\n')
+      f.write('#ifndef APIENTRY\n')
+      f.write('#define APIENTRY\n')
+      f.write('#endif\n')
+      f.write('#ifndef APIENTRYP\n')
+      f.write('#define APIENTRYP APIENTRY *\n')
+      f.write('#endif\n')
+      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
+      f.write('#endif\n')
+
+      f.write('#ifndef GL_OES_EGL_image\n')
+      f.write('typedef void *GLeglImageOES;\n')
+      f.write('#endif\n')
+
+      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
+      f.write('typedef GLint GLfixed;\n')
+      f.write('#endif\n')
+
+      f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\n')
+      f.write('typedef long long int GLint64;\n')
+      f.write('typedef unsigned long long int GLuint64;\n')
+      f.write('typedef unsigned long long int GLuint64EXT;\n')
+      f.write('typedef struct __GLsync *GLsync;\n')
+      f.write('#endif\n')
+
+      dump(f, typedefs)
+      dump(f, overrides)
+      dump(f, externs)
+
+      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
+      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')
+
+      f.write('#ifdef __cplusplus\n')
+      f.write('}\n')
+      f.write('#endif\n')
+
+      f.write('#endif\n')
+
+   with open(sys.argv[3], 'w') as f:
+      f.write('#include "glsym/glsym.h"\n')
+      f.write('#include <stddef.h>\n')
+      f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
+      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
+      dump(f, macros)
+      f.write('    { NULL, NULL },\n')
+      f.write('};\n')
+      dump(f, declarations)
diff --git a/deps/libretro-common/hash/lrc_hash.c b/deps/libretro-common/hash/lrc_hash.c
new file mode 100644 (file)
index 0000000..98ce132
--- /dev/null
@@ -0,0 +1,576 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (lrc_hash.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <string.h>
+#include <stdio.h>
+#ifdef _WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include <lrc_hash.h>
+#include <retro_miscellaneous.h>
+#include <retro_endianness.h>
+#include <streams/file_stream.h>
+
+#define LSL32(x, n) ((uint32_t)(x) << (n))
+#define LSR32(x, n) ((uint32_t)(x) >> (n))
+#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))
+
+/* First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19 */
+static const uint32_t T_H[8] = {
+   0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
+};
+
+/* First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311 */
+static const uint32_t T_K[64] = {
+   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+};
+
+/* SHA256 implementation from bSNES. Written by valditx. */
+
+struct sha256_ctx
+{
+   union
+   {
+      uint8_t u8[64];
+      uint32_t u32[16];
+   } in;
+   unsigned inlen;
+
+   uint32_t w[64];
+   uint32_t h[8];
+   uint64_t len;
+};
+
+static void sha256_init(struct sha256_ctx *p)
+{
+   memset(p, 0, sizeof(struct sha256_ctx));
+   memcpy(p->h, T_H, sizeof(T_H));
+}
+
+static void sha256_block(struct sha256_ctx *p)
+{
+   unsigned i;
+   uint32_t s0, s1;
+   uint32_t a, b, c, d, e, f, g, h;
+
+   for (i = 0; i < 16; i++)
+      p->w[i] = load32be(p->in.u32 + i);
+
+   for (i = 16; i < 64; i++)
+   {
+      s0 = ROR32(p->w[i - 15],  7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15],  3);
+      s1 = ROR32(p->w[i -  2], 17) ^ ROR32(p->w[i -  2], 19) ^ LSR32(p->w[i -  2], 10);
+      p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;
+   }
+
+   a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];
+   e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];
+
+   for (i = 0; i < 64; i++)
+   {
+      uint32_t t1, t2, maj, ch;
+
+      s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
+      maj = (a & b) ^ (a & c) ^ (b & c);
+      t2  = s0 + maj;
+      s1  = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
+      ch  = (e & f) ^ (~e & g);
+      t1  = h + s1 + ch + T_K[i] + p->w[i];
+
+      h   = g;
+      g   = f;
+      f   = e;
+      e   = d + t1;
+      d   = c;
+      c   = b;
+      b   = a;
+      a   = t1 + t2;
+   }
+
+   p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;
+   p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;
+
+   /* Next block */
+   p->inlen = 0;
+}
+
+static void sha256_chunk(struct sha256_ctx *p,
+      const uint8_t *s, unsigned len)
+{
+   p->len += len;
+
+   while (len)
+   {
+      unsigned l = 64 - p->inlen;
+
+      if (len < l)
+         l       = len;
+
+      memcpy(p->in.u8 + p->inlen, s, l);
+
+      s         += l;
+      p->inlen  += l;
+      len       -= l;
+
+      if (p->inlen == 64)
+         sha256_block(p);
+   }
+}
+
+static void sha256_final(struct sha256_ctx *p)
+{
+   uint64_t len;
+   p->in.u8[p->inlen++] = 0x80;
+
+   if (p->inlen > 56)
+   {
+      memset(p->in.u8 + p->inlen, 0, 64 - p->inlen);
+      sha256_block(p);
+   }
+
+   memset(p->in.u8 + p->inlen, 0, 56 - p->inlen);
+
+   len = p->len << 3;
+   store32be(p->in.u32 + 14, (uint32_t)(len >> 32));
+   store32be(p->in.u32 + 15, (uint32_t)len);
+   sha256_block(p);
+}
+
+static void sha256_subhash(struct sha256_ctx *p, uint32_t *t)
+{
+   unsigned i;
+   for (i = 0; i < 8; i++)
+      store32be(t++, p->h[i]);
+}
+
+/**
+ * sha256_hash:
+ * @s                 : Output.
+ * @in                : Input.
+ * @size              : Size of @s.
+ *
+ * Hashes SHA256 and outputs a human readable string.
+ **/
+void sha256_hash(char *s, const uint8_t *in, size_t size)
+{
+   unsigned i;
+   struct sha256_ctx sha;
+
+   union
+   {
+      uint32_t u32[8];
+      uint8_t u8[32];
+   } shahash;
+
+   sha256_init(&sha);
+   sha256_chunk(&sha, in, (unsigned)size);
+   sha256_final(&sha);
+   sha256_subhash(&sha, shahash.u32);
+
+   for (i = 0; i < 32; i++)
+      snprintf(s + 2 * i, 3, "%02x", (unsigned)shahash.u8[i]);
+}
+
+#ifndef HAVE_ZLIB
+/* Zlib CRC32. */
+static const uint32_t crc32_hash_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_t crc32_adjust(uint32_t checksum, uint8_t input)
+{
+   return ((checksum >> 8) & 0x00ffffff) ^ crc32_hash_table[(checksum ^ input) & 0xff];
+}
+
+uint32_t crc32_calculate(const uint8_t *data, size_t length)
+{
+   size_t i;
+   uint32_t checksum = ~0;
+   for (i = 0; i < length; i++)
+      checksum = crc32_adjust(checksum, data[i]);
+   return ~checksum;
+}
+#endif
+
+/* SHA-1 implementation. */
+
+/*
+ *  sha1.c
+ *
+ *  Copyright (C) 1998, 2009
+ *  Paul E. Jones <paulej@packetizer.com>
+ *  All Rights Reserved
+ *
+ *****************************************************************************
+ *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
+ *****************************************************************************
+ *
+ *  Description:
+ *      This file implements the Secure Hashing Standard as defined
+ *      in FIPS PUB 180-1 published April 17, 1995.
+ *
+ *      The Secure Hashing Standard, which uses the Secure Hashing
+ *      Algorithm (SHA), produces a 160-bit message digest for a
+ *      given data stream.  In theory, it is highly improbable that
+ *      two messages will produce the same message digest.  Therefore,
+ *      this algorithm can serve as a means of providing a "fingerprint"
+ *      for a message.
+ *
+ *  Portability Issues:
+ *      SHA-1 is defined in terms of 32-bit "words".  This code was
+ *      written with the expectation that the processor has at least
+ *      a 32-bit machine word size.  If the machine word size is larger,
+ *      the code should still function properly.  One caveat to that
+ *      is that the input functions taking characters and character
+ *      arrays assume that only 8 bits of information are stored in each
+ *      character.
+ *
+ *  Caveats:
+ *      SHA-1 is designed to work with messages less than 2^64 bits
+ *      long. Although SHA-1 allows a message digest to be generated for
+ *      messages of any number of bits less than 2^64, this
+ *      implementation only works with messages with a length that is a
+ *      multiple of the size of an 8-bit character.
+ *
+ */
+
+/* Define the circular shift macro */
+#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
+
+struct sha1_context
+{
+   unsigned Message_Digest[5]; /* Message Digest (output)          */
+
+   unsigned Length_Low;        /* Message length in bits           */
+   unsigned Length_High;       /* Message length in bits           */
+
+   unsigned char Message_Block[64]; /* 512-bit message blocks      */
+   int Message_Block_Index;    /* Index into message block array   */
+
+   int Computed;               /* Is the digest computed?          */
+   int Corrupted;              /* Is the message digest corruped?  */
+};
+
+
+static void SHA1Reset(struct sha1_context *context)
+{
+   if (!context)
+      return;
+
+   context->Length_Low             = 0;
+   context->Length_High            = 0;
+   context->Message_Block_Index    = 0;
+
+   context->Message_Digest[0]      = 0x67452301;
+   context->Message_Digest[1]      = 0xEFCDAB89;
+   context->Message_Digest[2]      = 0x98BADCFE;
+   context->Message_Digest[3]      = 0x10325476;
+   context->Message_Digest[4]      = 0xC3D2E1F0;
+
+   context->Computed   = 0;
+   context->Corrupted  = 0;
+}
+
+static void SHA1ProcessMessageBlock(struct sha1_context *context)
+{
+   const unsigned K[] =            /* Constants defined in SHA-1   */
+   {
+      0x5A827999,
+      0x6ED9EBA1,
+      0x8F1BBCDC,
+      0xCA62C1D6
+   };
+   int         t;                  /* Loop counter                 */
+   unsigned    temp;               /* Temporary word value         */
+   unsigned    W[80];              /* Word sequence                */
+   unsigned    A, B, C, D, E;      /* Word buffers                 */
+
+   /* Initialize the first 16 words in the array W */
+   for (t = 0; t < 16; t++)
+   {
+      W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
+      W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
+      W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
+      W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
+   }
+
+   for (t = 16; t < 80; t++)
+      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+
+   A = context->Message_Digest[0];
+   B = context->Message_Digest[1];
+   C = context->Message_Digest[2];
+   D = context->Message_Digest[3];
+   E = context->Message_Digest[4];
+
+   for (t = 0; t < 20; t++)
+   {
+      temp  =  SHA1CircularShift(5,A) +
+         ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+      temp &= 0xFFFFFFFF;
+      E     = D;
+      D     = C;
+      C     = SHA1CircularShift(30,B);
+      B     = A;
+      A     = temp;
+   }
+
+   for (t = 20; t < 40; t++)
+   {
+      temp  = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+      temp &= 0xFFFFFFFF;
+      E     = D;
+      D     = C;
+      C     = SHA1CircularShift(30,B);
+      B     = A;
+      A     = temp;
+   }
+
+   for (t = 40; t < 60; t++)
+   {
+      temp  = SHA1CircularShift(5,A) +
+         ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+      temp &= 0xFFFFFFFF;
+      E     = D;
+      D     = C;
+      C     = SHA1CircularShift(30,B);
+      B     = A;
+      A     = temp;
+   }
+
+   for (t = 60; t < 80; t++)
+   {
+      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+      temp &= 0xFFFFFFFF;
+      E = D;
+      D = C;
+      C = SHA1CircularShift(30,B);
+      B = A;
+      A = temp;
+   }
+
+   context->Message_Digest[0] =
+      (context->Message_Digest[0] + A) & 0xFFFFFFFF;
+   context->Message_Digest[1] =
+      (context->Message_Digest[1] + B) & 0xFFFFFFFF;
+   context->Message_Digest[2] =
+      (context->Message_Digest[2] + C) & 0xFFFFFFFF;
+   context->Message_Digest[3] =
+      (context->Message_Digest[3] + D) & 0xFFFFFFFF;
+   context->Message_Digest[4] =
+      (context->Message_Digest[4] + E) & 0xFFFFFFFF;
+
+   context->Message_Block_Index = 0;
+}
+
+static void SHA1PadMessage(struct sha1_context *context)
+{
+   if (!context)
+      return;
+
+   /*
+    *  Check to see if the current message block is too small to hold
+    *  the initial padding bits and length.  If so, we will pad the
+    *  block, process it, and then continue padding into a second
+    *  block.
+    */
+   context->Message_Block[context->Message_Block_Index++] = 0x80;
+
+   if (context->Message_Block_Index > 55)
+   {
+      while (context->Message_Block_Index < 64)
+         context->Message_Block[context->Message_Block_Index++] = 0;
+
+      SHA1ProcessMessageBlock(context);
+   }
+
+   while (context->Message_Block_Index < 56)
+      context->Message_Block[context->Message_Block_Index++] = 0;
+
+   /*  Store the message length as the last 8 octets */
+   context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
+   context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
+   context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
+   context->Message_Block[59] = (context->Length_High) & 0xFF;
+   context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
+   context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
+   context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
+   context->Message_Block[63] = (context->Length_Low) & 0xFF;
+
+   SHA1ProcessMessageBlock(context);
+}
+
+static int SHA1Result(struct sha1_context *context)
+{
+   if (context->Corrupted)
+      return 0;
+
+   if (!context->Computed)
+   {
+      SHA1PadMessage(context);
+      context->Computed = 1;
+   }
+
+   return 1;
+}
+
+static void SHA1Input(struct sha1_context *context,
+      const unsigned char *message_array,
+      unsigned length)
+{
+   if (!length)
+      return;
+
+   if (context->Computed || context->Corrupted)
+   {
+      context->Corrupted = 1;
+      return;
+   }
+
+   while (length-- && !context->Corrupted)
+   {
+      context->Message_Block[context->Message_Block_Index++] =
+         (*message_array & 0xFF);
+
+      context->Length_Low += 8;
+      /* Force it to 32 bits */
+      context->Length_Low &= 0xFFFFFFFF;
+      if (context->Length_Low == 0)
+      {
+         context->Length_High++;
+         /* Force it to 32 bits */
+         context->Length_High &= 0xFFFFFFFF;
+         if (context->Length_High == 0)
+            context->Corrupted = 1; /* Message is too long */
+      }
+
+      if (context->Message_Block_Index == 64)
+         SHA1ProcessMessageBlock(context);
+
+      message_array++;
+   }
+}
+
+int sha1_calculate(const char *path, char *result)
+{
+   struct sha1_context sha;
+   unsigned char buff[4096];
+   int rv    = 1;
+   RFILE *fd = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+   if (!fd)
+      goto error;
+
+   buff[0] = '\0';
+
+   SHA1Reset(&sha);
+
+   do
+   {
+      rv = (int)filestream_read(fd, buff, 4096);
+      if (rv < 0)
+         goto error;
+
+      SHA1Input(&sha, buff, rv);
+   } while (rv);
+
+   if (!SHA1Result(&sha))
+      goto error;
+
+   sprintf(result, "%08X%08X%08X%08X%08X",
+         sha.Message_Digest[0],
+         sha.Message_Digest[1],
+         sha.Message_Digest[2],
+         sha.Message_Digest[3], sha.Message_Digest[4]);
+
+   filestream_close(fd);
+   return 0;
+
+error:
+   if (fd)
+      filestream_close(fd);
+   return -1;
+}
+
+uint32_t djb2_calculate(const char *str)
+{
+   const unsigned char *aux = (const unsigned char*)str;
+   uint32_t            hash = 5381;
+
+   while ( *aux )
+      hash = ( hash << 5 ) + hash + *aux++;
+
+   return hash;
+}
diff --git a/deps/libretro-common/include/array/rbuf.h b/deps/libretro-common/include/array/rbuf.h
new file mode 100644 (file)
index 0000000..deb045f
--- /dev/null
@@ -0,0 +1,120 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rbuf.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_ARRAY_RBUF_H__
+#define __LIBRETRO_SDK_ARRAY_RBUF_H__
+
+/*
+ * This file implements stretchy buffers as invented (?) by Sean Barrett.
+ * Based on the implementation from the public domain Bitwise project
+ * by Per Vognsen - https://github.com/pervognsen/bitwise
+ *
+ * It's a super simple type safe dynamic array for C with no need
+ * to predeclare any type or anything.
+ * The first time an element is added, memory for 16 elements are allocated.
+ * Then every time length is about to exceed capacity, capacity is doubled.
+ *
+ * Be careful not to supply modifying statements to the macro arguments.
+ * Something like RBUF_REMOVE(buf, i--); would have unintended results.
+ *
+ * Sample usage:
+ *
+ * mytype_t* buf = NULL;
+ * RBUF_PUSH(buf, some_element);
+ * RBUF_PUSH(buf, other_element);
+ * -- now RBUF_LEN(buf) == 2, buf[0] == some_element, buf[1] == other_element
+ *
+ * -- Free allocated memory:
+ * RBUF_FREE(buf);
+ * -- now buf == NULL, RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 0
+ *
+ * -- Explicitly increase allocated memory and set capacity:
+ * RBUF_FIT(buf, 100);
+ * -- now RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 100
+ * 
+ * -- Resize buffer (does not initialize or zero memory!)
+ * RBUF_RESIZE(buf, 200);
+ * -- now RBUF_LEN(buf) == 200, RBUF_CAP(buf) == 200
+ * 
+ * -- To handle running out of memory:
+ * bool ran_out_of_memory = !RBUF_TRYFIT(buf, 1000);
+ * -- before RESIZE or PUSH. When out of memory, buf will stay unmodified.
+ */
+
+#include <retro_math.h> /* for MAX */
+#include <stdlib.h> /* for malloc, realloc */
+
+#define RBUF__HDR(b) (((struct rbuf__hdr *)(b))-1)
+
+#define RBUF_LEN(b) ((b) ? RBUF__HDR(b)->len : 0)
+#define RBUF_CAP(b) ((b) ? RBUF__HDR(b)->cap : 0)
+#define RBUF_END(b) ((b) + RBUF_LEN(b))
+#define RBUF_SIZEOF(b) ((b) ? RBUF_LEN(b)*sizeof(*b) : 0)
+
+#define RBUF_FREE(b) ((b) ? (free(RBUF__HDR(b)), (b) = NULL) : 0)
+#define RBUF_FIT(b, n) ((size_t)(n) <= RBUF_CAP(b) ? 0 : (*(void**)(&(b)) = rbuf__grow((b), (n), sizeof(*(b)))))
+#define RBUF_PUSH(b, val) (RBUF_FIT((b), 1 + RBUF_LEN(b)), (b)[RBUF__HDR(b)->len++] = (val))
+#define RBUF_POP(b) (b)[--RBUF__HDR(b)->len]
+#define RBUF_RESIZE(b, sz) (RBUF_FIT((b), (sz)), ((b) ? RBUF__HDR(b)->len = (sz) : 0))
+#define RBUF_CLEAR(b) ((b) ? RBUF__HDR(b)->len = 0 : 0)
+#define RBUF_TRYFIT(b, n) (RBUF_FIT((b), (n)), (((b) && RBUF_CAP(b) >= (size_t)(n)) || !(n)))
+#define RBUF_REMOVE(b, idx) memmove((b) + (idx), (b) + (idx) + 1, (--RBUF__HDR(b)->len - (idx)) * sizeof(*(b)))
+
+struct rbuf__hdr
+{
+   size_t len;
+   size_t cap;
+};
+
+#ifdef __GNUC__
+__attribute__((__unused__))
+#elif defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4505) //unreferenced local function has been removed
+#endif
+static void *rbuf__grow(void *buf,
+      size_t new_len, size_t elem_size)
+{
+   struct rbuf__hdr *new_hdr;
+   size_t new_cap  = MAX(2 * RBUF_CAP(buf), MAX(new_len, 16));
+   size_t new_size = sizeof(struct rbuf__hdr) + new_cap*elem_size;
+   if (buf)
+   {
+      new_hdr      = (struct rbuf__hdr *)realloc(RBUF__HDR(buf), new_size);
+      if (!new_hdr)
+         return buf; /* out of memory, return unchanged */
+   }
+   else
+   {
+      new_hdr      = (struct rbuf__hdr *)malloc(new_size);
+      if (!new_hdr)
+         return NULL; /* out of memory */
+      new_hdr->len = 0;
+   }
+   new_hdr->cap    = new_cap;
+   return new_hdr + 1;
+}
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/array/rhmap.h b/deps/libretro-common/include/array/rhmap.h
new file mode 100644 (file)
index 0000000..d6aec90
--- /dev/null
@@ -0,0 +1,285 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rhmap.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_ARRAY_RHMAP_H__
+#define __LIBRETRO_SDK_ARRAY_RHMAP_H__
+
+/*
+ * This file implements a hash map with 32-bit keys.
+ * Based on the implementation from the public domain Bitwise project
+ * by Per Vognsen - https://github.com/pervognsen/bitwise
+ *
+ * It's a super simple type safe hash map for C with no need
+ * to predeclare any type or anything.
+ * Will always allocate memory for twice the amount of max elements
+ * so larger structs should be stored as pointers or indices to an array.
+ * Can be used in C++ with POD types (without any constructor/destructor).
+ *
+ * Be careful not to supply modifying statements to the macro arguments.
+ * Something like RHMAP_FIT(map, i++); would have unintended results.
+ *
+ * Sample usage:
+ *
+ * -- Set 2 elements with string keys and mytype_t values:
+ * mytype_t* map = NULL;
+ * RHMAP_SET_STR(map, "foo", foo_element);
+ * RHMAP_SET_STR(map, "bar", bar_element);
+ * -- now RHMAP_LEN(map) == 2, RHMAP_GET_STR(map, "foo") == foo_element
+ *
+ * -- Check if keys exist:
+ * bool has_foo = RHMAP_HAS_STR(map, "foo");
+ * bool has_baz = RHMAP_HAS_STR(map, "baz");
+ * -- now has_foo == true, has_baz == false
+ *
+ * -- Removing a key:
+ * bool removed = RHMAP_DEL_STR(map, "bar");
+ * bool removed_again = RHMAP_DEL_STR(map, "bar");
+ * -- now RHMAP_LEN(map) == 1, removed == true, removed_again == false
+ *
+ * -- Add/modify via pointer:
+ * mytype_t* p_elem = RHMAP_PTR_STR(map, "qux");
+ * p_elem->a = 123;
+ * -- New keys initially have memory uninitialized
+ * -- Pointers can get invalidated when a key is added/removed
+ *
+ * -- Looking up the index for a given key:
+ * ptrdiff_t idx_foo = RHMAP_IDX_STR(map, "foo");
+ * ptrdiff_t idx_invalid = RHMAP_IDX_STR(map, "invalid");
+ * -- now idx_foo >= 0, idx_invalid == -1, map[idx_foo] == foo_element
+ * -- Indices can change when a key is added/removed
+ *
+ * -- Clear all elements (keep memory allocated):
+ * RHMAP_CLEAR(map);
+ * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 16
+ *
+ * -- Reserve memory for at least N elements:
+ * RHMAP_FIT(map, 30);
+ * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 64
+ *
+ * -- Add elements with custom hash keys:
+ * RHMAP_SET(map, my_uint32_hash(key1), some_element);
+ * RHMAP_SET(map, my_uint32_hash(key2), other_element);
+ * -- now RHMAP_LEN(map) == 2, _GET/_HAS/_DEL/_PTR/_IDX also exist
+ *
+ * -- Iterate elements (random order, order can change on insert):
+ * for (size_t i = 0, cap = RHMAP_CAP(map); i != cap, i++)
+ *   if (RHMAP_KEY(map, i))
+ * ------ here map[i] is the value of key RHMAP_KEY(map, i)
+ *
+ * -- Set a custom null value (is zeroed by default):
+ * RHMAP_SETNULLVAL(map, map_null);
+ * -- now RHMAP_GET_STR(map, "invalid") == map_null
+ *
+ * -- Free allocated memory:
+ * RHMAP_FREE(map);
+ * -- now map == NULL, RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 0
+ *
+ * -- To handle running out of memory:
+ * bool ran_out_of_memory = !RHMAP_TRYFIT(map, 1000);
+ * -- before setting an element (with SET, PTR or NULLVAL).
+ * -- When out of memory, map will stay unmodified.
+ *
+ */
+
+#include <stdlib.h> /* for malloc, realloc */
+#include <string.h> /* for memcpy, memset */
+#include <stddef.h> /* for ptrdiff_t, size_t */
+#include <stdint.h> /* for uint32_t */
+
+#define RHMAP_LEN(b) ((b) ? RHMAP__HDR(b)->len : 0)
+#define RHMAP_MAX(b) ((b) ? RHMAP__HDR(b)->maxlen : 0)
+#define RHMAP_CAP(b) ((b) ? RHMAP__HDR(b)->maxlen + 1 : 0)
+#define RHMAP_KEY(b, idx) (RHMAP__HDR(b)->keys[idx])
+#define RHMAP_KEY_STR(b, idx) (RHMAP__HDR(b)->key_strs[idx])
+#define RHMAP_SETNULLVAL(b, val) (RHMAP__FIT1(b), b[-1] = (val))
+#define RHMAP_CLEAR(b) ((b) ? (memset(RHMAP__HDR(b)->keys, 0, RHMAP_CAP(b) * sizeof(uint32_t)), RHMAP__HDR(b)->len = 0) : 0)
+#define RHMAP_FREE(b) ((b) ? (rhmap__free(RHMAP__HDR(b)), (b) = NULL) : 0)
+#define RHMAP_FIT(b, n) ((!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))) ? 0 : RHMAP__GROW(b, n))
+#define RHMAP_TRYFIT(b, n) (RHMAP_FIT((b), (n)), (!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))))
+
+#define RHMAP_SET(b, key, val) RHMAP_SET_FULL(b, key, NULL, val)
+#define RHMAP_GET(b, key)      RHMAP_GET_FULL(b, key, NULL)
+#define RHMAP_HAS(b, key)      RHMAP_HAS_FULL(b, key, NULL)
+#define RHMAP_DEL(b, key)      RHMAP_DEL_FULL(b, key, NULL)
+#define RHMAP_PTR(b, key)      RHMAP_PTR_FULL(b, key, NULL)
+#define RHMAP_IDX(b, key)      RHMAP_IDX_FULL(b, key, NULL)
+
+#ifdef __GNUC__
+#define RHMAP__UNUSED __attribute__((__unused__))
+#else
+#define RHMAP__UNUSED
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:4505) //unreferenced local function has been removed
+#endif
+
+#define RHMAP_SET_FULL(b, key, str, val) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)] = (val))
+#define RHMAP_GET_FULL(b, key, str) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0)])
+#define RHMAP_HAS_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) != -1 : 0)
+#define RHMAP_DEL_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, sizeof(*(b))) != -1 : 0)
+#define RHMAP_PTR_FULL(b, key, str) (RHMAP__FIT1(b), &b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)])
+#define RHMAP_IDX_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) : -1)
+
+#define RHMAP_SET_STR(b, string_key, val) RHMAP_SET_FULL(b, rhmap_hash_string(string_key), string_key, val)
+#define RHMAP_GET_STR(b, string_key)      RHMAP_GET_FULL(b, rhmap_hash_string(string_key), string_key)
+#define RHMAP_HAS_STR(b, string_key)      RHMAP_HAS_FULL(b, rhmap_hash_string(string_key), string_key)
+#define RHMAP_DEL_STR(b, string_key)      RHMAP_DEL_FULL(b, rhmap_hash_string(string_key), string_key)
+#define RHMAP_PTR_STR(b, string_key)      RHMAP_PTR_FULL(b, rhmap_hash_string(string_key), string_key)
+#define RHMAP_IDX_STR(b, string_key)      RHMAP_IDX_FULL(b, rhmap_hash_string(string_key), string_key)
+
+RHMAP__UNUSED static uint32_t rhmap_hash_string(const char* str)
+{
+   unsigned char c;
+   uint32_t hash = (uint32_t)0x811c9dc5;
+   while ((c = (unsigned char)*(str++)) != '\0')
+      hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);
+   return (hash ? hash : 1);
+}
+
+struct rhmap__hdr { size_t len, maxlen; uint32_t *keys; char** key_strs; };
+#define RHMAP__HDR(b) (((struct rhmap__hdr *)&(b)[-1])-1)
+#define RHMAP__GROW(b, n) (*(void**)(&(b)) = rhmap__grow((void*)(b), sizeof(*(b)), (size_t)(n)))
+#define RHMAP__FIT1(b) ((b) && RHMAP_LEN(b) * 2 <= RHMAP_MAX(b) ? 0 : RHMAP__GROW(b, 0))
+
+RHMAP__UNUSED static void* rhmap__grow(void* old_ptr, size_t elem_size, size_t reserve)
+{
+   struct rhmap__hdr *old_hdr = (old_ptr ? ((struct rhmap__hdr *)((char*)old_ptr-elem_size))-1 : NULL);
+   struct rhmap__hdr *new_hdr;
+   char *new_vals;
+   size_t new_max = (old_ptr ? old_hdr->maxlen * 2 + 1 : 15);
+   for (; new_max / 2 <= reserve; new_max = new_max * 2 + 1)
+      if (new_max == (size_t)-1)
+         return old_ptr; /* overflow */
+
+   new_hdr = (struct rhmap__hdr *)malloc(sizeof(struct rhmap__hdr) + (new_max + 2) * elem_size);
+   if (!new_hdr)
+      return old_ptr; /* out of memory */
+
+   new_hdr->maxlen = new_max;
+   new_hdr->keys = (uint32_t *)calloc(new_max + 1, sizeof(uint32_t));
+   if (!new_hdr->keys)
+   {
+      /* out of memory */
+      free(new_hdr);
+      return old_ptr;
+   }
+   new_hdr->key_strs = (char**)calloc(new_max + 1, sizeof(char*));
+   if (!new_hdr->key_strs)
+   {
+      /* out of memory */
+      free(new_hdr->keys);
+      free(new_hdr);
+      return old_ptr;
+   }
+
+   new_vals = ((char*)(new_hdr + 1)) + elem_size;
+   if (old_ptr)
+   {
+      size_t i;
+      char* old_vals = ((char*)(old_hdr + 1)) + elem_size;
+      for (i = 0; i <= old_hdr->maxlen; i++)
+      {
+         uint32_t key, j;
+         if (!old_hdr->keys[i])
+            continue;
+         for (key = old_hdr->keys[i], j = key;; j++)
+         {
+            if (!new_hdr->keys[j &= new_hdr->maxlen])
+            {
+               new_hdr->keys[j] = key;
+               new_hdr->key_strs[j] = old_hdr->key_strs[i];
+               memcpy(new_vals + j * elem_size, old_vals + i * elem_size, elem_size);
+               break;
+            }
+         }
+      }
+      memcpy(new_vals - elem_size, old_vals - elem_size, elem_size);
+      new_hdr->len = old_hdr->len;
+      free(old_hdr->keys);
+      free(old_hdr->key_strs);
+      free(old_hdr);
+   }
+   else
+   {
+      memset(new_vals - elem_size, 0, elem_size);
+      new_hdr->len = 0;
+   }
+   return new_vals;
+}
+
+RHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key, const char * str, int add, size_t del)
+{
+   uint32_t i;
+
+   if (!key)
+      return (ptrdiff_t)-1;
+
+   for (i = key;; i++)
+   {
+      if (hdr->keys[i &= hdr->maxlen] == key && (!hdr->key_strs[i] || !str || !strcmp(hdr->key_strs[i], str)))
+      {
+         if (del)
+         {
+            hdr->len--;
+            hdr->keys[i] = 0;
+            free(hdr->key_strs[i]);
+            hdr->key_strs[i] = NULL;
+            while ((key = hdr->keys[i = (i + 1) & hdr->maxlen]) != 0)
+            {
+               if ((key = (uint32_t)rhmap__idx(hdr, key, hdr->key_strs[i], 1, 0)) == i) continue;
+               hdr->len--;
+               hdr->keys[i] = 0;
+               free(hdr->key_strs[i]);
+               hdr->key_strs[i] = NULL;
+               memcpy(((char*)(hdr + 1)) + (key + 1) * del,
+                     ((char*)(hdr + 1)) + (i + 1) * del, del);
+            }
+         }
+         return (ptrdiff_t)i;
+      }
+      if (!hdr->keys[i])
+      {
+         if (add) { hdr->len++; hdr->keys[i] = key; if (str) hdr->key_strs[i] = strdup(str); return (ptrdiff_t)i; }
+         return (ptrdiff_t)-1;
+      }
+   }
+}
+
+RHMAP__UNUSED static void rhmap__free(struct rhmap__hdr* hdr)
+{
+   size_t i;
+   for (i=0;i<hdr->maxlen+1;i++)
+   {
+      free(hdr->key_strs[i]);
+   }
+   free(hdr->key_strs);
+   free(hdr->keys);
+   free(hdr);
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/audio/audio_mix.h b/deps/libretro-common/include/audio/audio_mix.h
new file mode 100644 (file)
index 0000000..6a2adac
--- /dev/null
@@ -0,0 +1,94 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (audio_mix.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_AUDIO_MIX_H__
+#define __LIBRETRO_SDK_AUDIO_MIX_H__
+
+#include <retro_common_api.h>
+
+#include <stdint.h>
+#include <stddef.h>
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <formats/rwav.h>
+#include <audio/audio_resampler.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct
+{
+   double ratio;
+   void *buf;
+   int16_t *upsample_buf;
+   float *float_buf;
+   float *float_resample_buf;
+   int16_t *resample_buf;
+   const retro_resampler_t *resampler;
+   void *resampler_data;
+   rwav_t *rwav;
+   ssize_t len;
+   size_t resample_len;
+   int sample_rate;
+   bool resample;
+} audio_chunk_t;
+
+#if defined(__SSE2__)
+#define audio_mix_volume           audio_mix_volume_SSE2
+
+void audio_mix_volume_SSE2(float *out,
+      const float *in, float vol, size_t samples);
+#else
+#define audio_mix_volume           audio_mix_volume_C
+#endif
+
+void audio_mix_volume_C(float *dst, const float *src, float vol, size_t samples);
+
+void audio_mix_free_chunk(audio_chunk_t *chunk);
+
+audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,
+      const char *resampler_ident, enum resampler_quality quality);
+
+size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk);
+
+/**
+ * audio_mix_get_chunk_sample:
+ * @chunk              : audio chunk instance
+ * @channel            : channel of the sample (0=left, 1=right)
+ * @index              : index of the sample
+ *
+ * Get a sample from an audio chunk.
+ *
+ * Returns: A signed 16-bit audio sample, (if necessary) resampled into the desired output rate.
+ **/
+int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t sample);
+
+int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk);
+
+int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/audio/audio_mixer.h b/deps/libretro-common/include/audio/audio_mixer.h
new file mode 100644 (file)
index 0000000..6b07bbe
--- /dev/null
@@ -0,0 +1,90 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (audio_mixer.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_AUDIO_MIXER__H
+#define __LIBRETRO_SDK_AUDIO_MIXER__H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <boolean.h>
+#include <retro_common_api.h>
+
+#include <audio/audio_resampler.h>
+
+RETRO_BEGIN_DECLS
+
+enum audio_mixer_type
+{
+   AUDIO_MIXER_TYPE_NONE = 0,
+   AUDIO_MIXER_TYPE_WAV,
+   AUDIO_MIXER_TYPE_OGG,
+   AUDIO_MIXER_TYPE_MOD,
+   AUDIO_MIXER_TYPE_FLAC,
+   AUDIO_MIXER_TYPE_MP3
+};
+
+typedef struct audio_mixer_sound audio_mixer_sound_t;
+typedef struct audio_mixer_voice audio_mixer_voice_t;
+
+typedef void (*audio_mixer_stop_cb_t)(audio_mixer_sound_t* sound, unsigned reason);
+
+/* Reasons passed to the stop callback. */
+#define AUDIO_MIXER_SOUND_FINISHED 0
+#define AUDIO_MIXER_SOUND_STOPPED  1
+#define AUDIO_MIXER_SOUND_REPEATED 2
+
+void audio_mixer_init(unsigned rate);
+
+void audio_mixer_done(void);
+
+audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,
+      const char *resampler_ident, enum resampler_quality quality);
+audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size);
+audio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size);
+audio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size);
+audio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size);
+
+void audio_mixer_destroy(audio_mixer_sound_t* sound);
+
+audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,
+      bool repeat, float volume,
+      const char *resampler_ident,
+      enum resampler_quality quality,
+      audio_mixer_stop_cb_t stop_cb);
+
+void audio_mixer_stop(audio_mixer_voice_t* voice);
+
+float audio_mixer_voice_get_volume(audio_mixer_voice_t *voice);
+
+void audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val);
+
+void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bool override);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/audio/audio_resampler.h b/deps/libretro-common/include/audio/audio_resampler.h
new file mode 100644 (file)
index 0000000..cdb09c2
--- /dev/null
@@ -0,0 +1,223 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (audio_resampler.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H
+#define __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <boolean.h>
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#define RESAMPLER_SIMD_SSE      (1 << 0)
+#define RESAMPLER_SIMD_SSE2     (1 << 1)
+#define RESAMPLER_SIMD_VMX      (1 << 2)
+#define RESAMPLER_SIMD_VMX128   (1 << 3)
+#define RESAMPLER_SIMD_AVX      (1 << 4)
+#define RESAMPLER_SIMD_NEON     (1 << 5)
+#define RESAMPLER_SIMD_SSE3     (1 << 6)
+#define RESAMPLER_SIMD_SSSE3    (1 << 7)
+#define RESAMPLER_SIMD_MMX      (1 << 8)
+#define RESAMPLER_SIMD_MMXEXT   (1 << 9)
+#define RESAMPLER_SIMD_SSE4     (1 << 10)
+#define RESAMPLER_SIMD_SSE42    (1 << 11)
+#define RESAMPLER_SIMD_AVX2     (1 << 12)
+#define RESAMPLER_SIMD_VFPU     (1 << 13)
+#define RESAMPLER_SIMD_PS       (1 << 14)
+
+enum resampler_quality
+{
+   RESAMPLER_QUALITY_DONTCARE = 0,
+   RESAMPLER_QUALITY_LOWEST,
+   RESAMPLER_QUALITY_LOWER,
+   RESAMPLER_QUALITY_NORMAL,
+   RESAMPLER_QUALITY_HIGHER,
+   RESAMPLER_QUALITY_HIGHEST
+};
+
+/* A bit-mask of all supported SIMD instruction sets.
+ * Allows an implementation to pick different
+ * resampler_implementation structs.
+ */
+typedef unsigned resampler_simd_mask_t;
+
+#define RESAMPLER_API_VERSION 1
+
+/**
+ * A struct that groups the input and output of a resampler.
+ */
+struct resampler_data
+{
+   /**
+    * The buffer containing the data to be resampled.
+    */
+   const float *data_in;
+
+   /**
+    * The buffer that will be used to store resampled output.
+    * Must be allocated in advance, and must not be the same as data_in.
+    */
+   float *data_out;
+
+   /**
+    * The size of ::data_in, in frames (\em not bytes or samples).
+    * For example, 32-bit stereo frames would consist of 8 bytes
+    * (two 4-byte floats per frame).
+    */
+   size_t input_frames;
+
+   /**
+    * The number of frames (\em not bytes or samples) that the resampler produced.
+    * This value is set by the resampler.
+    * The resampler may not provide the same number of frames with each use,
+    * so be sure to check this value.
+    */
+   size_t output_frames;
+
+   /**
+    * The desired ratio of output_frames to input_frames.
+    * This value is used to determine the number of frames written to \c data_out.
+    * If this value is (almost) equal to 1,
+    * then resampling may be skipped.
+    */
+   double ratio;
+};
+
+/* Returns true if config key was found. Otherwise,
+ * returns false, and sets value to default value.
+ */
+typedef int (*resampler_config_get_float_t)(void *userdata,
+      const char *key, float *value, float default_value);
+
+typedef int (*resampler_config_get_int_t)(void *userdata,
+      const char *key, int *value, int default_value);
+
+/* Allocates an array with values. free() with resampler_config_free_t. */
+typedef int (*resampler_config_get_float_array_t)(void *userdata,
+      const char *key, float **values, unsigned *out_num_values,
+      const float *default_values, unsigned num_default_values);
+
+typedef int (*resampler_config_get_int_array_t)(void *userdata,
+      const char *key, int **values, unsigned *out_num_values,
+      const int *default_values, unsigned num_default_values);
+
+typedef int (*resampler_config_get_string_t)(void *userdata,
+      const char *key, char **output, const char *default_output);
+
+/* Calls free() in host runtime. Sometimes needed on Windows.
+ * free() on NULL is fine. */
+typedef void (*resampler_config_free_t)(void *ptr);
+
+struct resampler_config
+{
+   resampler_config_get_float_t get_float;
+   resampler_config_get_int_t get_int;
+
+   resampler_config_get_float_array_t get_float_array;
+   resampler_config_get_int_array_t get_int_array;
+
+   resampler_config_get_string_t get_string;
+   /* Avoid problems where resampler plug and host are
+    * linked against different C runtimes. */
+   resampler_config_free_t free;
+};
+
+/* Bandwidth factor. Will be < 1.0 for downsampling, > 1.0 for upsampling.
+ * Corresponds to expected resampling ratio. */
+typedef void *(*resampler_init_t)(const struct resampler_config *config,
+      double bandwidth_mod, enum resampler_quality quality,
+      resampler_simd_mask_t mask);
+
+/* Frees the handle. */
+typedef void (*resampler_free_t)(void *data);
+
+/* Processes input data. */
+typedef void (*resampler_process_t)(void *_data, struct resampler_data *data);
+
+typedef struct retro_resampler
+{
+   resampler_init_t     init;
+   resampler_process_t  process;
+   resampler_free_t     free;
+
+   /* Must be RESAMPLER_API_VERSION */
+   unsigned api_version;
+
+   /* Human readable identifier of implementation. */
+   const char *ident;
+
+   /* Computer-friendly short version of ident.
+    * Lower case, no spaces and special characters, etc. */
+   const char *short_ident;
+} retro_resampler_t;
+
+typedef struct audio_frame_float
+{
+   float l;
+   float r;
+} audio_frame_float_t;
+
+extern retro_resampler_t sinc_resampler;
+#ifdef HAVE_CC_RESAMPLER
+extern retro_resampler_t CC_resampler;
+#endif
+extern retro_resampler_t nearest_resampler;
+
+/**
+ * audio_resampler_driver_find_handle:
+ * @index              : index of driver to get handle to.
+ *
+ * Returns: handle to audio resampler driver at index. Can be NULL
+ * if nothing found.
+ **/
+const void *audio_resampler_driver_find_handle(int index);
+
+/**
+ * audio_resampler_driver_find_ident:
+ * @index              : index of driver to get handle to.
+ *
+ * Returns: Human-readable identifier of audio resampler driver at index.
+ * Can be NULL if nothing found.
+ **/
+const char *audio_resampler_driver_find_ident(int index);
+
+/**
+ * retro_resampler_realloc:
+ * @re                         : Resampler handle
+ * @backend                    : Resampler backend that is about to be set.
+ * @ident                      : Identifier name for resampler we want.
+ * @bw_ratio                   : Bandwidth ratio.
+ *
+ * Reallocates resampler. Will free previous handle before
+ * allocating a new one. If ident is NULL, first resampler will be used.
+ *
+ * Returns: true (1) if successful, otherwise false (0).
+ **/
+bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
+      const char *ident, enum resampler_quality quality, double bw_ratio);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/audio/conversion/dual_mono.h b/deps/libretro-common/include/audio/conversion/dual_mono.h
new file mode 100644 (file)
index 0000000..e0f59ba
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright  (C) 2010-2023 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (s16_to_float.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_CONVERSION_DUAL_MONO__
+#define __LIBRETRO_SDK_CONVERSION_DUAL_MONO__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * Duplicates 1-channel (mono) frames into 2-channel (stereo) frames.
+ * The resulting array is suitable for use in the resampler,
+ * or for any use case that demands stereo input.
+ * This version operates on 32-bit floating-point samples.
+ *
+ * May use SIMD intrinsics on supported platforms,
+ * but will work without them.
+ *
+ * Will do nothing if \c out or \c in are \c NULL.
+ *
+ * @param[out] out The location in which the converted frames will be stored.
+ * Must have enough room for twice the value of \c frames.
+ * @param[in] in The location of the frames to convert.
+ * @param[in] frames The number of frames to convert.
+ */
+void convert_to_dual_mono_float(float *out, const float *in, size_t frames);
+
+/**
+ * Downmixes 2-channel (stereo) frames into 1-channel (mono) frames.
+ * This is intended for dual-mono audio (i.e. where both channels are identical),
+ * but it will work if both channels are different.
+ *
+ * This version operates on 32-bit floating-point samples.
+ * It preserves the left channel and ignores the right channel.
+ *
+ * Will do nothing if \c out or \c in are \c NULL.
+ *
+ * @param[out] out The location in which the converted frames will be stored.
+ * Must have enough room for half the value of <code>frames * sizeof(float)</code>.
+ * @param[in] in The location of the frames to convert.
+ * @param[in] frames The number of frames to convert.
+ */
+void convert_to_mono_float_left(float *out, const float *in, size_t frames);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/audio/conversion/float_to_s16.h b/deps/libretro-common/include/audio/conversion/float_to_s16.h
new file mode 100644 (file)
index 0000000..42b9571
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright  (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (float_to_s16.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__
+#define __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#include <stdint.h>
+#include <stddef.h>
+
+/**
+ * convert_float_to_s16:
+ * @out               : output buffer
+ * @in                : input buffer
+ * @samples           : size of samples to be converted
+ *
+ * Converts floating point
+ * to signed integer 16-bit.
+ **/
+void convert_float_to_s16(int16_t *out,
+      const float *in, size_t samples);
+
+/**
+ * convert_float_to_s16_init_simd:
+ *
+ * Sets up function pointers for conversion
+ * functions based on CPU features.
+ **/
+void convert_float_to_s16_init_simd(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/audio/conversion/s16_to_float.h b/deps/libretro-common/include/audio/conversion/s16_to_float.h
new file mode 100644 (file)
index 0000000..188296e
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright  (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (s16_to_float.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__
+#define __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * convert_s16_to_float:
+ * @out               : output buffer
+ * @in                : input buffer
+ * @samples           : size of samples to be converted
+ * @gain              : gain applied (.e.g. audio volume)
+ *
+ * Converts from signed integer 16-bit
+ * to floating point.
+ **/
+void convert_s16_to_float(float *out,
+      const int16_t *in, size_t samples, float gain);
+
+/**
+ * convert_s16_to_float_init_simd:
+ *
+ * Sets up function pointers for conversion
+ * functions based on CPU features.
+ **/
+void convert_s16_to_float_init_simd(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/audio/dsp_filter.h b/deps/libretro-common/include/audio/dsp_filter.h
new file mode 100644 (file)
index 0000000..fc5be20
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (dsp_filter.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_AUDIO_DSP_FILTER_H
+#define __LIBRETRO_SDK_AUDIO_DSP_FILTER_H
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct retro_dsp_filter retro_dsp_filter_t;
+
+retro_dsp_filter_t *retro_dsp_filter_new(const char *filter_config,
+      void *string_data, float sample_rate);
+
+void retro_dsp_filter_free(retro_dsp_filter_t *dsp);
+
+/**
+ * A struct that groups the input and output of a DSP filter.
+ */
+struct retro_dsp_data
+{
+   float *input;
+   unsigned input_frames;
+
+   /* Set by retro_dsp_filter_process(). */
+   float *output;
+   unsigned output_frames;
+};
+
+void retro_dsp_filter_process(retro_dsp_filter_t *dsp,
+      struct retro_dsp_data *data);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/boolean.h b/deps/libretro-common/include/boolean.h
new file mode 100644 (file)
index 0000000..9d0d7c1
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (boolean.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_BOOLEAN_H
+#define __LIBRETRO_SDK_BOOLEAN_H
+
+#ifndef __cplusplus
+
+#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
+/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
+#define bool unsigned char
+#define true 1
+#define false 0
+#else
+#include <stdbool.h>
+#endif
+
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/cdrom/cdrom.h b/deps/libretro-common/include/cdrom/cdrom.h
new file mode 100644 (file)
index 0000000..063d9ac
--- /dev/null
@@ -0,0 +1,125 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (cdrom.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_CDROM_H
+#define __LIBRETRO_SDK_CDROM_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <vfs/vfs.h>
+#include <libretro.h>
+#include <retro_common_api.h>
+#include <retro_inline.h>
+
+#include <boolean.h>
+
+struct string_list;
+
+RETRO_BEGIN_DECLS
+
+typedef struct
+{
+   unsigned short g1_timeout;
+   unsigned short g2_timeout;
+   unsigned short g3_timeout;
+} cdrom_group_timeouts_t;
+
+typedef struct
+{
+   unsigned lba_start; /* start of pregap */
+   unsigned lba; /* start of data */
+   unsigned track_size; /* in LBAs */
+   unsigned track_bytes;
+   unsigned char track_num;
+   unsigned char min; /* start of data */
+   unsigned char sec;
+   unsigned char frame;
+   unsigned char mode;
+   bool audio;
+} cdrom_track_t;
+
+typedef struct
+{
+   cdrom_track_t track[99];         /* unsigned alignment */
+   cdrom_group_timeouts_t timeouts; /* unsigned short alignment */
+   unsigned char num_tracks;
+   char drive;
+} cdrom_toc_t;
+
+void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);
+
+unsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame);
+
+void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame);
+
+int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *buf, size_t len);
+
+int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc);
+
+/* needs 32 bytes for full vendor, product and version */
+int cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *model, int len, bool *is_cdrom);
+
+int cdrom_read(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip);
+
+int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed);
+
+int cdrom_stop(libretro_vfs_implementation_file *stream);
+
+int cdrom_unlock(libretro_vfs_implementation_file *stream);
+
+int cdrom_open_tray(libretro_vfs_implementation_file *stream);
+
+int cdrom_close_tray(libretro_vfs_implementation_file *stream);
+
+/* must be freed by the caller */
+struct string_list* cdrom_get_available_drives(void);
+
+bool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream);
+
+bool cdrom_drive_has_media(const char drive);
+
+void cdrom_get_current_config_core(libretro_vfs_implementation_file *stream);
+
+void cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream);
+
+void cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream);
+
+void cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream);
+
+void cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream);
+
+int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len);
+
+bool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled);
+
+bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts);
+
+bool cdrom_has_atip(libretro_vfs_implementation_file *stream);
+
+void cdrom_device_fillpath(char *path, size_t len, char drive, unsigned char track, bool is_cue);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/clamping.h b/deps/libretro-common/include/clamping.h
new file mode 100644 (file)
index 0000000..d836d98
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (clamping.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_CLAMPING_H
+#define _LIBRETRO_SDK_CLAMPING_H
+
+#include <stdint.h>
+#include <retro_inline.h>
+
+/**
+ * clamp_float:
+ * @val           : initial value
+ * @lower         : lower limit that value should be clamped against
+ * @upper         : upper limit that value should be clamped against
+ *
+ * Clamps a floating point value.
+ *
+ * Returns: a clamped value of initial float value @val.
+ */
+static INLINE float clamp_float(float val, float lower, float upper)
+{
+   if (val < lower)
+      return lower;
+   if (val > upper)
+      return upper;
+   return val;
+}
+
+/**
+ * clamp_8bit:
+ * @val           : initial value
+ *
+ * Clamps an unsigned 8-bit value.
+ *
+ * Returns: a clamped value of initial unsigned 8-bit value @val.
+ */
+static INLINE uint8_t clamp_8bit(int val)
+{
+   if (val > 255)
+      return 255;
+   if (val < 0)
+      return 0;
+   return (uint8_t)val;
+}
+
+#endif
diff --git a/deps/libretro-common/include/compat/apple_compat.h b/deps/libretro-common/include/compat/apple_compat.h
new file mode 100644 (file)
index 0000000..bf98a59
--- /dev/null
@@ -0,0 +1,84 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (apple_compat.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __APPLE_COMPAT_H
+#define __APPLE_COMPAT_H
+
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+#endif
+
+#ifdef __OBJC__
+
+#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4)
+typedef int NSInteger;
+typedef unsigned NSUInteger;
+typedef float CGFloat;
+#endif
+
+#ifndef __has_feature
+/* Compatibility with non-Clang compilers. */
+#define __has_feature(x) 0
+#endif
+
+#ifndef CF_RETURNS_RETAINED
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#else
+#define CF_RETURNS_RETAINED
+#endif
+#endif
+
+#ifndef NS_INLINE
+#define NS_INLINE inline
+#endif
+
+NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X)
+{
+#if __has_feature(objc_arc)
+   return (__bridge_retained CFTypeRef)X;
+#else
+   return X;
+#endif
+}
+
+#endif
+
+#ifdef IOS
+#ifndef __IPHONE_5_0
+#warning "This project uses features only available in iOS SDK 5.0 and later."
+#endif
+
+#ifdef __OBJC__
+#import <UIKit/UIKit.h>
+#import <GLKit/GLKit.h>
+#import <Foundation/Foundation.h>
+#endif
+
+#else
+
+#ifdef __OBJC__
+#include <objc/objc-runtime.h>
+#endif
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/compat/fnmatch.h b/deps/libretro-common/include/compat/fnmatch.h
new file mode 100644 (file)
index 0000000..9787878
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fnmatch.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_FNMATCH_H__
+#define __LIBRETRO_SDK_COMPAT_FNMATCH_H__
+
+#define        FNM_NOMATCH     1
+
+int rl_fnmatch(const char *pattern, const char *string, int flags);
+
+#endif
diff --git a/deps/libretro-common/include/compat/fopen_utf8.h b/deps/libretro-common/include/compat/fopen_utf8.h
new file mode 100644 (file)
index 0000000..97d4404
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fopen_utf8.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
+#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
+
+#ifdef _WIN32
+/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */
+/* TODO: enable */
+/* #define fopen (use fopen_utf8 instead) */
+void *fopen_utf8(const char * filename, const char * mode);
+#else
+#define fopen_utf8 fopen
+#endif
+#endif
diff --git a/deps/libretro-common/include/compat/getopt.h b/deps/libretro-common/include/compat/getopt.h
new file mode 100644 (file)
index 0000000..48603f0
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (getopt.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_GETOPT_H
+#define __LIBRETRO_SDK_COMPAT_GETOPT_H
+
+#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
+#include "../../../config.h"
+#endif
+
+/* Custom implementation of the GNU getopt_long for portability.
+ * Not designed to be fully compatible, but compatible with
+ * the features RetroArch uses. */
+
+#ifdef HAVE_GETOPT_LONG
+#include <getopt.h>
+#else
+/* Avoid possible naming collisions during link since we
+ * prefer to use the actual name. */
+#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex)
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+struct option
+{
+   const char *name;
+   int has_arg;
+   int *flag;
+   int val;
+};
+
+/* argv[] is declared with char * const argv[] in GNU,
+ * but this makes no sense, as non-POSIX getopt_long
+ * mutates argv (non-opts are moved to the end). */
+int getopt_long(int argc, char *argv[],
+      const char *optstring, const struct option *longopts, int *longindex);
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+RETRO_END_DECLS
+
+/* If these are variously #defined, then we have bigger problems */
+#ifndef no_argument
+   #define no_argument 0
+   #define required_argument 1
+   #define optional_argument 2
+#endif
+
+/* HAVE_GETOPT_LONG */
+#endif
+
+/* pragma once */
+#endif
diff --git a/deps/libretro-common/include/compat/ifaddrs.h b/deps/libretro-common/include/compat/ifaddrs.h
new file mode 100644 (file)
index 0000000..2dc6848
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1995, 1999
+ *     Berkeley Software Design, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
+ *
+ *     BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef        _IFADDRS_H_
+#define        _IFADDRS_H_
+
+struct ifaddrs
+{
+   struct ifaddrs  *ifa_next;
+   char                *ifa_name;
+   unsigned int         ifa_flags;
+   struct sockaddr     *ifa_addr;
+   struct sockaddr     *ifa_netmask;
+   struct sockaddr     *ifa_dstaddr;
+   void                *ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef        ifa_broadaddr
+#define        ifa_broadaddr   ifa_dstaddr     /* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+extern int getifaddrs(struct ifaddrs **ifap);
+extern void freeifaddrs(struct ifaddrs *ifa);
+
+#endif
diff --git a/deps/libretro-common/include/compat/intrinsics.h b/deps/libretro-common/include/compat/intrinsics.h
new file mode 100644 (file)
index 0000000..ac49027
--- /dev/null
@@ -0,0 +1,99 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (intrinsics.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_INTRINSICS_H
+#define __LIBRETRO_SDK_COMPAT_INTRINSICS_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <retro_common_api.h>
+#include <retro_inline.h>
+
+#if defined(_MSC_VER) && !defined(_XBOX)
+#if (_MSC_VER > 1310)
+#include <intrin.h>
+#endif
+#endif
+
+RETRO_BEGIN_DECLS
+
+/* Count Leading Zero, unsigned 16bit input value */
+static INLINE unsigned compat_clz_u16(uint16_t val)
+{
+#if defined(__GNUC__)
+   return __builtin_clz(val << 16 | 0x8000);
+#else
+   unsigned ret = 0;
+
+   while(!(val & 0x8000) && ret < 16)
+   {
+      val <<= 1;
+      ret++;
+   }
+
+   return ret;
+#endif
+}
+
+/* Count Trailing Zero */
+static INLINE int compat_ctz(unsigned x)
+{
+#if defined(__GNUC__) && !defined(RARCH_CONSOLE)
+   return __builtin_ctz(x);
+#elif _MSC_VER >= 1400 && !defined(_XBOX) && !defined(__WINRT__)
+   unsigned long r = 0;
+   _BitScanForward((unsigned long*)&r, x);
+   return (int)r;
+#else
+   int count = 0;
+   if (!(x & 0xffff))
+   {
+      x >>= 16;
+      count |= 16;
+   }
+   if (!(x & 0xff))
+   {
+      x >>= 8;
+      count |= 8;
+   }
+   if (!(x & 0xf))
+   {
+      x >>= 4;
+      count |= 4;
+   }
+   if (!(x & 0x3))
+   {
+      x >>= 2;
+      count |= 2;
+   }
+   if (!(x & 0x1))
+      count |= 1;
+
+   return count;
+#endif
+}
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/compat/msvc.h b/deps/libretro-common/include/compat/msvc.h
new file mode 100644 (file)
index 0000000..a4c93a5
--- /dev/null
@@ -0,0 +1,126 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (msvc.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_MSVC_H
+#define __LIBRETRO_SDK_COMPAT_MSVC_H
+
+#ifdef _MSC_VER
+
+#ifdef __cplusplus
+extern "C"  {
+#endif
+
+/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
+#if _MSC_VER < 1900
+   #include <stdio.h>
+   #include <stdarg.h>
+   #include <stdlib.h>
+
+   #ifndef snprintf
+      #define snprintf c99_snprintf_retro__
+   #endif
+   int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
+
+   #ifndef vsnprintf
+      #define vsnprintf c99_vsnprintf_retro__
+   #endif
+   int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#undef UNICODE /* Do not bother with UNICODE at this time. */
+#include <direct.h>
+#include <stddef.h>
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+/* Python headers defines ssize_t and sets HAVE_SSIZE_T.
+ * Cannot duplicate these efforts.
+ */
+#ifndef HAVE_SSIZE_T
+#if defined(_WIN64)
+typedef __int64 ssize_t;
+#elif defined(_WIN32)
+typedef int ssize_t;
+#endif
+#endif
+
+#define mkdir(dirname, unused) _mkdir(dirname)
+#define strtoull _strtoui64
+#undef strcasecmp
+#define strcasecmp _stricmp
+#undef strncasecmp
+#define strncasecmp _strnicmp
+
+/* Disable some of the annoying warnings. */
+#pragma warning(disable : 4800)
+#pragma warning(disable : 4805)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4146)
+#pragma warning(disable : 4267)
+#pragma warning(disable : 4723)
+#pragma warning(disable : 4996)
+
+/* roundf and va_copy is available since MSVC 2013 */
+#if _MSC_VER < 1800
+#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
+#define va_copy(x, y) ((x) = (y))
+#endif
+
+#if _MSC_VER <= 1310
+   #ifndef __cplusplus
+      /* VC6 math.h doesn't define some functions when in C mode.
+       * Trying to define a prototype gives "undefined reference".
+       * But providing an implementation then gives "function already has body".
+       * So the equivalent of the implementations from math.h are used as
+       * defines here instead, and it seems to work.
+       */
+      #define cosf(x) ((float)cos((double)x))
+      #define powf(x, y) ((float)pow((double)x, (double)y))
+      #define sinf(x) ((float)sin((double)x))
+      #define ceilf(x) ((float)ceil((double)x))
+      #define floorf(x) ((float)floor((double)x))
+      #define sqrtf(x) ((float)sqrt((double)x))
+      #define fabsf(x)    ((float)fabs((double)(x)))
+   #endif
+
+   #ifndef _strtoui64
+      #define _strtoui64(x, y, z) (_atoi64(x))
+   #endif
+
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _MAX_PATH
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX _UI32_MAX
+#endif
+
+#endif
+#endif
diff --git a/deps/libretro-common/include/compat/msvc/stdint.h b/deps/libretro-common/include/compat/msvc/stdint.h
new file mode 100644 (file)
index 0000000..7c91a68
--- /dev/null
@@ -0,0 +1,255 @@
+/* ISO C9x  compliant stdint.h for Microsoft Visual Studio
+ * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+ *
+ * Copyright (c) 2006-2008 Alexander Chemeris
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may 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.
+ */
+
+#ifndef __RARCH_STDINT_H
+#define __RARCH_STDINT_H
+
+#if _MSC_VER && (_MSC_VER < 1600)
+/* Pre-MSVC 2010 needs an implementation of stdint.h. */
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+ * compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+ * or compiler give many errors like this:
+ *
+ * error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+ */
+#ifdef __cplusplus
+#if _MSC_VER <= 1200
+extern "C++" {
+#else
+extern "C" {
+#endif
+#endif
+#  include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+/* Define _W64 macros to mark types changing their size, like intptr_t. */
+#ifndef _W64
+#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#     define _W64 __w64
+#  else
+#     define _W64
+#  endif
+#endif
+
+/* 7.18.1 Integer types. */
+
+/* 7.18.1.1 Exact-width integer types. */
+
+/* Visual Studio 6 and Embedded Visual C++ 4 doesn't
+ * realize that, e.g. char has the same size as __int8
+ * so we give up on __intX for them.
+ */
+#if (_MSC_VER < 1300)
+   typedef signed char       int8_t;
+   typedef signed short      int16_t;
+   typedef signed int        int32_t;
+   typedef unsigned char     uint8_t;
+   typedef unsigned short    uint16_t;
+   typedef unsigned int      uint32_t;
+#else
+   typedef signed __int8     int8_t;
+   typedef signed __int16    int16_t;
+   typedef signed __int32    int32_t;
+   typedef unsigned __int8   uint8_t;
+   typedef unsigned __int16  uint16_t;
+   typedef unsigned __int32  uint32_t;
+#endif
+typedef signed __int64       int64_t;
+typedef unsigned __int64     uint64_t;
+
+/* 7.18.1.2 Minimum-width integer types. */
+typedef int8_t    int_least8_t;
+typedef int16_t   int_least16_t;
+typedef int32_t   int_least32_t;
+typedef int64_t   int_least64_t;
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+typedef uint64_t  uint_least64_t;
+
+/* 7.18.1.3 Fastest minimum-width integer types. */
+typedef int8_t    int_fast8_t;
+typedef int16_t   int_fast16_t;
+typedef int32_t   int_fast32_t;
+typedef int64_t   int_fast64_t;
+typedef uint8_t   uint_fast8_t;
+typedef uint16_t  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+typedef uint64_t  uint_fast64_t;
+
+/* 7.18.1.4 Integer types capable of holding object pointers. */
+#ifdef _WIN64 /* [ */
+   typedef signed __int64    intptr_t;
+   typedef unsigned __int64  uintptr_t;
+#else /* _WIN64 ][ */
+   typedef _W64 signed int   intptr_t;
+   typedef _W64 unsigned int uintptr_t;
+#endif /* _WIN64 ] */
+
+/* 7.18.1.5 Greatest-width integer types. */
+typedef int64_t   intmax_t;
+typedef uint64_t  uintmax_t;
+
+/* 7.18.2 Limits of specified-width integer types. */
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+/* [   See footnote 220 at page 257 and footnote 221 at page 259. */
+
+/* 7.18.2.1 Limits of exact-width integer types. */
+#define INT8_MIN     ((int8_t)_I8_MIN)
+#define INT8_MAX     _I8_MAX
+#define INT16_MIN    ((int16_t)_I16_MIN)
+#define INT16_MAX    _I16_MAX
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    _I32_MAX
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    _I64_MAX
+#define UINT8_MAX    _UI8_MAX
+#define UINT16_MAX   _UI16_MAX
+#define UINT32_MAX   _UI32_MAX
+#define UINT64_MAX   _UI64_MAX
+
+/* 7.18.2.2 Limits of minimum-width integer types. */
+#define INT_LEAST8_MIN    INT8_MIN
+#define INT_LEAST8_MAX    INT8_MAX
+#define INT_LEAST16_MIN   INT16_MIN
+#define INT_LEAST16_MAX   INT16_MAX
+#define INT_LEAST32_MIN   INT32_MIN
+#define INT_LEAST32_MAX   INT32_MAX
+#define INT_LEAST64_MIN   INT64_MIN
+#define INT_LEAST64_MAX   INT64_MAX
+#define UINT_LEAST8_MAX   UINT8_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+#define UINT_LEAST64_MAX  UINT64_MAX
+
+/* 7.18.2.3 Limits of fastest minimum-width integer types. */
+#define INT_FAST8_MIN    INT8_MIN
+#define INT_FAST8_MAX    INT8_MAX
+#define INT_FAST16_MIN   INT16_MIN
+#define INT_FAST16_MAX   INT16_MAX
+#define INT_FAST32_MIN   INT32_MIN
+#define INT_FAST32_MAX   INT32_MAX
+#define INT_FAST64_MIN   INT64_MIN
+#define INT_FAST64_MAX   INT64_MAX
+#define UINT_FAST8_MAX   UINT8_MAX
+#define UINT_FAST16_MAX  UINT16_MAX
+#define UINT_FAST32_MAX  UINT32_MAX
+#define UINT_FAST64_MAX  UINT64_MAX
+
+/* 7.18.2.4 Limits of integer types capable of holding object pointers. */
+#ifdef _WIN64 /* [ */
+#  define INTPTR_MIN   INT64_MIN
+#  define INTPTR_MAX   INT64_MAX
+#  define UINTPTR_MAX  UINT64_MAX
+#else /* _WIN64 ][ */
+#  define INTPTR_MIN   INT32_MIN
+#  define INTPTR_MAX   INT32_MAX
+#  define UINTPTR_MAX  UINT32_MAX
+#endif /* _WIN64 ] */
+
+/* 7.18.2.5 Limits of greatest-width integer types */
+#define INTMAX_MIN   INT64_MIN
+#define INTMAX_MAX   INT64_MAX
+#define UINTMAX_MAX  UINT64_MAX
+
+/* 7.18.3 Limits of other integer types */
+
+#ifdef _WIN64 /* [ */
+#  define PTRDIFF_MIN  _I64_MIN
+#  define PTRDIFF_MAX  _I64_MAX
+#else  /* _WIN64 ][ */
+#  define PTRDIFF_MIN  _I32_MIN
+#  define PTRDIFF_MAX  _I32_MAX
+#endif  /* _WIN64 ] */
+
+#define SIG_ATOMIC_MIN  INT_MIN
+#define SIG_ATOMIC_MAX  INT_MAX
+
+#ifndef SIZE_MAX /* [ */
+#  ifdef _WIN64 /* [ */
+#     define SIZE_MAX  _UI64_MAX
+#  else /* _WIN64 ][ */
+#     define SIZE_MAX  _UI32_MAX
+#  endif /* _WIN64 ] */
+#endif /* SIZE_MAX ] */
+
+/* WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> */
+#ifndef WCHAR_MIN /* [ */
+#  define WCHAR_MIN  0
+#endif  /* WCHAR_MIN ] */
+#ifndef WCHAR_MAX // [
+#  define WCHAR_MAX  _UI16_MAX
+#endif  /* WCHAR_MAX ] */
+
+#define WINT_MIN  0
+#define WINT_MAX  _UI16_MAX
+
+#endif /* __STDC_LIMIT_MACROS ] */
+
+/* 7.18.4 Limits of other integer types */
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+/* [   See footnote 224 at page 260 */
+
+/* 7.18.4.1 Macros for minimum-width integer constants */
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+/* 7.18.4.2 Macros for greatest-width integer constants */
+#define INTMAX_C   INT64_C
+#define UINTMAX_C  UINT64_C
+
+#endif
+/* __STDC_CONSTANT_MACROS ] */
+
+#else
+/* Sanity for everything else. */
+#include <stdint.h>
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/compat/posix_string.h b/deps/libretro-common/include/compat/posix_string.h
new file mode 100644 (file)
index 0000000..47964b2
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (posix_string.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
+#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
+
+#include <retro_common_api.h>
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+
+RETRO_BEGIN_DECLS
+
+#ifdef _WIN32
+#undef strtok_r
+#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)
+
+char *strtok_r(char *str, const char *delim, char **saveptr);
+#endif
+
+#ifdef _MSC_VER
+#undef strcasecmp
+#undef strdup
+#define strcasecmp(a, b) retro_strcasecmp__(a, b)
+#define strdup(orig)     retro_strdup__(orig)
+int strcasecmp(const char *a, const char *b);
+char *strdup(const char *orig);
+
+/* isblank is available since MSVC 2013 */
+#if _MSC_VER < 1800
+#undef isblank
+#define isblank(c)       retro_isblank__(c)
+int isblank(int c);
+#endif
+
+#endif
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/compat/strcasestr.h b/deps/libretro-common/include/compat/strcasestr.h
new file mode 100644 (file)
index 0000000..227e253
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (strcasestr.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_STRCASESTR_H
+#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H
+
+#include <string.h>
+
+#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
+#include "../../../config.h"
+#endif
+
+#ifndef HAVE_STRCASESTR
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/* Avoid possible naming collisions during link
+ * since we prefer to use the actual name. */
+#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)
+
+char *strcasestr(const char *haystack, const char *needle);
+
+RETRO_END_DECLS
+
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/compat/strl.h b/deps/libretro-common/include/compat/strl.h
new file mode 100644 (file)
index 0000000..5e7a892
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (strl.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_COMPAT_STRL_H
+#define __LIBRETRO_SDK_COMPAT_STRL_H
+
+#include <string.h>
+#include <stddef.h>
+
+#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
+#include "../../../config.h"
+#endif
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#ifdef __MACH__
+#ifndef HAVE_STRL
+#define HAVE_STRL
+#endif
+#endif
+
+#ifndef HAVE_STRL
+/* Avoid possible naming collisions during link since
+ * we prefer to use the actual name. */
+#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
+
+#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
+
+size_t strlcpy(char *dest, const char *source, size_t size);
+size_t strlcat(char *dest, const char *source, size_t size);
+
+#endif
+
+char *strldup(const char *s, size_t n);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/compat/zconf.h b/deps/libretro-common/include/compat/zconf.h
new file mode 100644 (file)
index 0000000..007b644
--- /dev/null
@@ -0,0 +1,483 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * 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 */
+#  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
+#  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 deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  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 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 gzvprintf             z_gzvprintf
+#    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 gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  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 inflateSetDictionary  z_inflateSetDictionary
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateResetKeep      z_inflateResetKeep
+#  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
+#  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
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#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 a few 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
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#  endif
+#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 <limits.h>
+#  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 <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* 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
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* 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/deps/libretro-common/include/compat/zconf.h.in b/deps/libretro-common/include/compat/zconf.h.in
new file mode 100644 (file)
index 0000000..007b644
--- /dev/null
@@ -0,0 +1,483 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * 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 */
+#  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
+#  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 deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  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 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 gzvprintf             z_gzvprintf
+#    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 gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  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 inflateSetDictionary  z_inflateSetDictionary
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateResetKeep      z_inflateResetKeep
+#  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
+#  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
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#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 a few 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
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#  endif
+#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 <limits.h>
+#  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 <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* 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
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* 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/deps/libretro-common/include/compat/zlib.h b/deps/libretro-common/include/compat/zlib.h
new file mode 100644 (file)
index 0000000..efd0a89
--- /dev/null
@@ -0,0 +1,1772 @@
+#ifndef _COMPAT_ZLIB_H
+#define _COMPAT_ZLIB_H
+
+#ifdef WANT_ZLIB
+
+#ifdef RARCH_INTERNAL
+#include "zconf.h.in"
+#endif
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.8, April 28th, 2013
+
+  Copyright (C) 1995-2013 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 <stdint.h>
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#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 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 case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);
+typedef void   (*free_func)  (voidpf opaque, voidpf address);
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    z_const Bytef *next_in;     /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total number of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    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 */
+    void *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 */
+    uLong   adler;      /* adler32 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.
+
+     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 in 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 (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ const char * zlibVersion (void);
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ int deflateInit (z_streamp strm, int level);
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     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().
+*/
+
+ int deflate (z_streamp strm, int flush);
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide 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 (in interactive applications).  Some
+    output may be provided even if flush is not set.
+
+    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.
+
+    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 code
+  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, 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 immediately after deflateInit if all the compression
+  is to be done in a single step.  In this case, 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 adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  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), 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.
+*/
+
+ int deflateEnd (z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+/*
+ int inflateInit (z_streamp strm);
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
+   exact value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  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
+   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 inflateInit() does not process any header information -- that is deferred
+   until inflate() is called.
+*/
+
+ int inflate (z_streamp strm, int flush);
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing will
+    resume at this point for the next call of inflate().
+
+  - Provide 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.  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.
+  Also to assist in this, on return inflate() will set 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 adler32
+  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, so applications that need that information should
+  instead use raw inflate, see inflateInit2() below, or inflateBack() and
+  perform their own processing of the gzip header and trailer.  When processing
+  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+  producted so far.  The CRC-32 is checked against the gzip trailer.
+
+    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), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is 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 desired.
+*/
+
+ int inflateEnd (z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent.  In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ int deflateInit2 (z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy);
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, 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.
+
+     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 an adler32 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 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     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().
+*/
+
+ int deflateSetDictionary (z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength);
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  When using the zlib format, this
+   function must be called immediately after deflateInit, deflateInit2 or
+   deflateReset, and before any call of deflate.  When doing raw deflate, this
+   function must be called either before any call of deflate, or immediately
+   after the completion of a deflate block, i.e. after all input has been
+   consumed and all output has been delivered when using any of the flush
+   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
+   compressor and decompressor must use exactly the same dictionary (see
+   inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The adler32 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
+   adler32 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().
+*/
+
+ int deflateCopy (z_streamp dest,
+                                    z_streamp source);
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ int deflateReset (z_streamp strm);
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.  The
+   stream will keep the same compression level and any other attributes that
+   may have been set by deflateInit2.
+
+     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).
+*/
+
+ int deflateParams (z_streamp strm,
+                                      int level,
+                                      int strategy);
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression level is changed, the input available so far is
+   compressed with the old level (and may be flushed); the new level will take
+   effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to be
+   compressed and flushed.  In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+   strm->avail_out was zero.
+*/
+
+ int deflateTune (z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain);
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ uLong deflateBound (z_streamp strm,
+                                       uLong sourceLen);
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().  If that first deflate() call is provided the
+   sourceLen input bytes, an output buffer allocated to the size returned by
+   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+   to return Z_STREAM_END.  Note that it is possible for the compressed size to
+   be larger than the value returned by deflateBound() if flush options other
+   than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ int deflatePending (z_streamp strm,
+                                       unsigned *pending,
+                                       int *bits);
+/*
+     deflatePending() returns the number of bytes and bits of output that have
+   been generated, but not yet provided in the available output.  The bytes not
+   provided would be due to the available output space having being consumed.
+   The number of bits of output not provided are between 0 and 7, where they
+   await more bits to join them in order to fill out a full byte.  If pending
+   or bits are Z_NULL, then those values are not set.
+
+     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+ */
+
+ int deflatePrime (z_streamp strm,
+                                     int bits,
+                                     int value);
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+   source stream state was inconsistent.
+*/
+
+ int deflateSetHeader (z_streamp strm,
+                                         gz_headerp head);
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 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.
+*/
+
+/*
+ int inflateInit2 (z_streamp strm,
+                                     int  windowBits);
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 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
+   crc32 instead of an adler32.
+
+     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.
+*/
+
+ int inflateSetDictionary (z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength);
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the adler32 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 adler32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ int inflateGetDictionary (z_streamp strm,
+                                             Bytef *dictionary,
+                                             uInt  *dictLength);
+/*
+     Returns the sliding dictionary being maintained by inflate.  dictLength is
+   set to the number of bytes in the dictionary, and that many bytes are copied
+   to dictionary.  dictionary must have enough space, where 32768 bytes is
+   always enough.  If inflateGetDictionary() is called with dictionary equal to
+   Z_NULL, then only the dictionary length is returned, and nothing is copied.
+   Similary, 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.
+*/
+
+ int inflateSync (z_streamp strm);
+/*
+     Skips invalid compressed data until a possible full flush point (see above
+   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+   All full flush points have this pattern, but not all occurrences of this
+   pattern are full flush points.
+
+     inflateSync returns Z_OK if a possible full flush point has been found,
+   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+   In the success case, the application may save the current 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.
+*/
+
+ int inflateCopy (z_streamp dest,
+                                    z_streamp source);
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ int inflateReset (z_streamp strm);
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all 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).
+*/
+
+ int inflateReset2 (z_streamp strm,
+                                      int windowBits);
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.
+
+     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.
+*/
+
+ int inflatePrime (z_streamp strm,
+                                     int bits,
+                                     int value);
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ long  inflateMark (z_streamp strm);
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above or -1 << 16 if the provided
+   source stream state was inconsistent.
+*/
+
+ int  inflateGetHeader (z_streamp strm,
+                                         gz_headerp head);
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ int  inflateBackInit (z_streamp strm, int windowBits,
+                                        unsigned char FAR *window);
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) (void FAR *,
+                                z_const unsigned char FAR * FAR *);
+typedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);
+
+ int  inflateBack (z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc);
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is potentially more efficient than
+   inflate() for file i/o applications, in that it avoids copying between the
+   output and the sliding window by simply making the window itself the output
+   buffer.  inflate() can be faster on modern CPUs when used with large
+   buffers.  inflateBack() trusts the application to not change the output
+   buffer passed by the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the normal
+   behavior of inflate(), which expects either a zlib or gzip 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.
+*/
+
+ int  inflateBackEnd (z_streamp strm);
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ uLong  zlibCompileFlags (void);
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ int  compress (Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen);
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     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.
+*/
+
+ int  compress2 (Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level);
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ uLong  compressBound (uLong sourceLen);
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ int  uncompress (Bytef *dest,   uLongf *destLen,
+       const Bytef *source, uLongf 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 buffer.
+
+     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.
+*/
+
+                        /* 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 */
+
+/*
+ gzFile  gzopen (const char *path, const char *mode);
+
+     Opens a gzip (.gz) file for reading or 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.
+*/
+
+ gzFile  gzdopen (int fd, const char *mode);
+/*
+     gzdopen associates 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).
+*/
+
+ int  gzbuffer (gzFile file, unsigned size);
+/*
+     Set the internal buffer size used by this library's functions.  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.  Two buffers are allocated, either both of the specified size when
+   writing, or one of the specified size and the other twice that size when
+   reading.  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.
+*/
+
+ int  gzsetparams (gzFile file, int level, int strategy);
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.
+
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ int  gzread (gzFile file, voidp buf, unsigned len);
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  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.
+*/
+
+ int  gzwrite (gzFile file,
+                                voidpc buf, unsigned len);
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ int gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or 0 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().
+*/
+
+ int  gzputs (gzFile file, const char *s);
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ char *  gzgets (gzFile file, char *buf, int len);
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or 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 == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, 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.
+*/
+
+ int  gzputc (gzFile file, int c);
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ int  gzgetc (gzFile file);
+/*
+     Reads one byte from the compressed 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.
+*/
+
+ int  gzungetc (int c, gzFile file);
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is 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().
+*/
+
+ int  gzflush (gzFile file, int flush);
+/*
+     Flushes all pending output into the compressed 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
+   concatented gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ z_off_t  gzseek (gzFile file,
+                                   z_off_t offset, int whence);
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed 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.
+*/
+
+ int     gzrewind (gzFile file);
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ z_off_t     gztell (gzFile file);
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed 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)
+*/
+
+/*
+ z_off_t  gzoffset (gzFile file);
+
+     Returns the current offset in the file being read or written.  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.
+*/
+
+ int  gzeof (gzFile file);
+/*
+     Returns true (1) if the end-of-file indicator 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.
+*/
+
+ int  gzdirect (gzFile file);
+/*
+     Returns 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.)
+*/
+
+ int     gzclose (gzFile file);
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates 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.
+*/
+
+ int  gzclose_r (gzFile file);
+ int  gzclose_w (gzFile file);
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ const char *  gzerror (gzFile file, int *errnum);
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed 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.
+*/
+
+ void  gzclearerr (gzFile file);
+/*
+     Clears 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.
+*/
+
+uint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  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 CRC32 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();
+*/
+
+/*
+ uLong  adler32_combine (uLong adler1, uLong adler2,
+                                          z_off_t len2);
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
+   that the z_off_t type (like off_t) is a signed integer.  If len2 is
+   negative, the result has no meaning or utility.
+*/
+
+ uLong  crc32   (uLong crc, const Bytef *buf, uInt len);
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  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();
+*/
+
+/*
+ uLong  crc32_combine (uLong crc1, uLong crc2, z_off_t len2);
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ int  deflateInit_ (z_streamp strm, int level,
+                                     const char *version, int stream_size);
+ int  inflateInit_ (z_streamp strm,
+                                     const char *version, int stream_size);
+ int  deflateInit2_ (z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size);
+ int  inflateInit2_ (z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size);
+ int  inflateBackInit_ (z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size);
+#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))
+
+#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.
+ */
+ int  gzgetc_ (gzFile file);  /* backward compatibility */
+#ifdef Z_PREFIX_SET
+#  undef z_gzgetc
+#  define z_gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+#  define gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+    gzFile  gzopen64 (const char *, const char *);
+    z_off64_t  gzseek64 (gzFile, z_off64_t, int);
+    z_off64_t  gztell64 (gzFile);
+    z_off64_t  gzoffset64 (gzFile);
+    uLong  adler32_combine64 (uLong, uLong, z_off64_t);
+    uLong  crc32_combine64 (uLong, uLong, 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
+#  else
+#    define gzopen gzopen64
+#    define gzseek gzseek64
+#    define gztell gztell64
+#    define gzoffset gzoffset64
+#    define adler32_combine adler32_combine64
+#    define crc32_combine crc32_combine64
+#  endif
+#  ifndef Z_LARGE64
+      gzFile  gzopen64 (const char *, const char *);
+      z_off_t  gzseek64 (gzFile, z_off_t, int);
+      z_off_t  gztell64 (gzFile);
+      z_off_t  gzoffset64 (gzFile);
+      uLong  adler32_combine64 (uLong, uLong, z_off_t);
+      uLong  crc32_combine64 (uLong, uLong, z_off_t);
+#  endif
+#else
+    gzFile  gzopen (const char *, const char *);
+    z_off_t  gzseek (gzFile, z_off_t, int);
+    z_off_t  gztell (gzFile);
+    z_off_t  gzoffset (gzFile);
+    uLong  adler32_combine (uLong, uLong, z_off_t);
+    uLong  crc32_combine (uLong, uLong, z_off_t);
+#endif
+
+#else /* Z_SOLO */
+
+    uLong  adler32_combine (uLong, uLong, z_off_t);
+    uLong  crc32_combine (uLong, uLong, z_off_t);
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ const char   *  zError           (int);
+ int             inflateSyncPoint (z_streamp);
+
+ const uint32_t * get_crc_table(void);
+ int             inflateUndermine (z_streamp, int);
+ int             inflateValidate  (z_streamp, int);
+ int             inflateResetKeep (z_streamp);
+ int             deflateResetKeep (z_streamp);
+#if defined(_WIN32) && !defined(Z_SOLO)
+ gzFile          gzopen_w (const wchar_t *path,
+                                            const char *mode);
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+ int            gzvprintf Z_ARG((gzFile file,
+                                                  const char *format,
+                                                  va_list va));
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
+
+#else
+#include <zlib.h>
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/compat/zlib/zconf.h b/deps/libretro-common/include/compat/zlib/zconf.h
new file mode 100644 (file)
index 0000000..007b644
--- /dev/null
@@ -0,0 +1,483 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * 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 */
+#  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
+#  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 deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  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 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 gzvprintf             z_gzvprintf
+#    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 gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  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 inflateSetDictionary  z_inflateSetDictionary
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateResetKeep      z_inflateResetKeep
+#  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
+#  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
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#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 a few 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
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#  endif
+#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 <limits.h>
+#  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 <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* 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
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* 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/deps/libretro-common/include/compat/zlib/zconf.h.in b/deps/libretro-common/include/compat/zlib/zconf.h.in
new file mode 100644 (file)
index 0000000..007b644
--- /dev/null
@@ -0,0 +1,483 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * 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 */
+#  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
+#  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 deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  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 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 gzvprintf             z_gzvprintf
+#    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 gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  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 inflateSetDictionary  z_inflateSetDictionary
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateResetKeep      z_inflateResetKeep
+#  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
+#  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
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#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 a few 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
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#  endif
+#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 <limits.h>
+#  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 <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* 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
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* 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/deps/libretro-common/include/compat/zlib/zlib.h b/deps/libretro-common/include/compat/zlib/zlib.h
new file mode 100644 (file)
index 0000000..800bdf5
--- /dev/null
@@ -0,0 +1,1761 @@
+#ifndef _COMPAT_ZLIB_H
+#define _COMPAT_ZLIB_H
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.8, April 28th, 2013
+
+  Copyright (C) 1995-2013 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 <stdint.h>
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#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 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 case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);
+typedef void   (*free_func)  (voidpf opaque, voidpf address);
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    z_const Bytef *next_in;     /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total number of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    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 */
+    void *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 */
+    uLong   adler;      /* adler32 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.
+
+     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 in 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 (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ const char * zlibVersion (void);
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ int deflateInit (z_streamp strm, int level);
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     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().
+*/
+
+ int deflate (z_streamp strm, int flush);
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide 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 (in interactive applications).  Some
+    output may be provided even if flush is not set.
+
+    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.
+
+    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 code
+  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, 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 immediately after deflateInit if all the compression
+  is to be done in a single step.  In this case, 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 adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  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), 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.
+*/
+
+ int deflateEnd (z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+/*
+ int inflateInit (z_streamp strm);
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
+   exact value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  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
+   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 inflateInit() does not process any header information -- that is deferred
+   until inflate() is called.
+*/
+
+ int inflate (z_streamp strm, int flush);
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing will
+    resume at this point for the next call of inflate().
+
+  - Provide 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.  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.
+  Also to assist in this, on return inflate() will set 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 adler32
+  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, so applications that need that information should
+  instead use raw inflate, see inflateInit2() below, or inflateBack() and
+  perform their own processing of the gzip header and trailer.  When processing
+  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+  producted so far.  The CRC-32 is checked against the gzip trailer.
+
+    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), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is 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 desired.
+*/
+
+ int inflateEnd (z_streamp strm);
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent.  In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ int deflateInit2 (z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy);
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, 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.
+
+     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 an adler32 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 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     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().
+*/
+
+ int deflateSetDictionary (z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength);
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  When using the zlib format, this
+   function must be called immediately after deflateInit, deflateInit2 or
+   deflateReset, and before any call of deflate.  When doing raw deflate, this
+   function must be called either before any call of deflate, or immediately
+   after the completion of a deflate block, i.e. after all input has been
+   consumed and all output has been delivered when using any of the flush
+   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
+   compressor and decompressor must use exactly the same dictionary (see
+   inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The adler32 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
+   adler32 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().
+*/
+
+ int deflateCopy (z_streamp dest,
+                                    z_streamp source);
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ int deflateReset (z_streamp strm);
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.  The
+   stream will keep the same compression level and any other attributes that
+   may have been set by deflateInit2.
+
+     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).
+*/
+
+ int deflateParams (z_streamp strm,
+                                      int level,
+                                      int strategy);
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression level is changed, the input available so far is
+   compressed with the old level (and may be flushed); the new level will take
+   effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to be
+   compressed and flushed.  In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+   strm->avail_out was zero.
+*/
+
+ int deflateTune (z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain);
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ uLong deflateBound (z_streamp strm,
+                                       uLong sourceLen);
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().  If that first deflate() call is provided the
+   sourceLen input bytes, an output buffer allocated to the size returned by
+   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+   to return Z_STREAM_END.  Note that it is possible for the compressed size to
+   be larger than the value returned by deflateBound() if flush options other
+   than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ int deflatePending (z_streamp strm,
+                                       unsigned *pending,
+                                       int *bits);
+/*
+     deflatePending() returns the number of bytes and bits of output that have
+   been generated, but not yet provided in the available output.  The bytes not
+   provided would be due to the available output space having being consumed.
+   The number of bits of output not provided are between 0 and 7, where they
+   await more bits to join them in order to fill out a full byte.  If pending
+   or bits are Z_NULL, then those values are not set.
+
+     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+ */
+
+ int deflatePrime (z_streamp strm,
+                                     int bits,
+                                     int value);
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+   source stream state was inconsistent.
+*/
+
+ int deflateSetHeader (z_streamp strm,
+                                         gz_headerp head);
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 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.
+*/
+
+/*
+ int inflateInit2 (z_streamp strm,
+                                     int  windowBits);
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 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
+   crc32 instead of an adler32.
+
+     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.
+*/
+
+ int inflateSetDictionary (z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength);
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the adler32 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 adler32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ int inflateGetDictionary (z_streamp strm,
+                                             Bytef *dictionary,
+                                             uInt  *dictLength);
+/*
+     Returns the sliding dictionary being maintained by inflate.  dictLength is
+   set to the number of bytes in the dictionary, and that many bytes are copied
+   to dictionary.  dictionary must have enough space, where 32768 bytes is
+   always enough.  If inflateGetDictionary() is called with dictionary equal to
+   Z_NULL, then only the dictionary length is returned, and nothing is copied.
+   Similary, 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.
+*/
+
+ int inflateSync (z_streamp strm);
+/*
+     Skips invalid compressed data until a possible full flush point (see above
+   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+   All full flush points have this pattern, but not all occurrences of this
+   pattern are full flush points.
+
+     inflateSync returns Z_OK if a possible full flush point has been found,
+   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+   In the success case, the application may save the current 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.
+*/
+
+ int inflateCopy (z_streamp dest,
+                                    z_streamp source);
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ int inflateReset (z_streamp strm);
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all 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).
+*/
+
+ int inflateReset2 (z_streamp strm,
+                                      int windowBits);
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.
+
+     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.
+*/
+
+ int inflatePrime (z_streamp strm,
+                                     int bits,
+                                     int value);
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ long  inflateMark (z_streamp strm);
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above or -1 << 16 if the provided
+   source stream state was inconsistent.
+*/
+
+ int  inflateGetHeader (z_streamp strm,
+                                         gz_headerp head);
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ int  inflateBackInit (z_streamp strm, int windowBits,
+                                        unsigned char FAR *window);
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) (void FAR *,
+                                z_const unsigned char FAR * FAR *);
+typedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);
+
+ int  inflateBack (z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc);
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is potentially more efficient than
+   inflate() for file i/o applications, in that it avoids copying between the
+   output and the sliding window by simply making the window itself the output
+   buffer.  inflate() can be faster on modern CPUs when used with large
+   buffers.  inflateBack() trusts the application to not change the output
+   buffer passed by the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the normal
+   behavior of inflate(), which expects either a zlib or gzip 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.
+*/
+
+ int  inflateBackEnd (z_streamp strm);
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ uLong  zlibCompileFlags (void);
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ int  compress (Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen);
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     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.
+*/
+
+ int  compress2 (Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level);
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ uLong  compressBound (uLong sourceLen);
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ int  uncompress (unsigned char *dest,   uint32_t *destLen,
+       const unsigned char *source, uint32_t 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 buffer.
+
+     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.
+*/
+
+                        /* 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 */
+
+/*
+ gzFile  gzopen (const char *path, const char *mode);
+
+     Opens a gzip (.gz) file for reading or 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.
+*/
+
+ gzFile  gzdopen (int fd, const char *mode);
+/*
+     gzdopen associates 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).
+*/
+
+ int  gzbuffer (gzFile file, unsigned size);
+/*
+     Set the internal buffer size used by this library's functions.  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.  Two buffers are allocated, either both of the specified size when
+   writing, or one of the specified size and the other twice that size when
+   reading.  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.
+*/
+
+ int  gzsetparams (gzFile file, int level, int strategy);
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.
+
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ int  gzread (gzFile file, voidp buf, unsigned len);
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  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.
+*/
+
+ int  gzwrite (gzFile file,
+                                voidpc buf, unsigned len);
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ int gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or 0 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().
+*/
+
+ int  gzputs (gzFile file, const char *s);
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ char *  gzgets (gzFile file, char *buf, int len);
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or 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 == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, 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.
+*/
+
+ int  gzputc (gzFile file, int c);
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ int  gzgetc (gzFile file);
+/*
+     Reads one byte from the compressed 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.
+*/
+
+ int  gzungetc (int c, gzFile file);
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is 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().
+*/
+
+ int  gzflush (gzFile file, int flush);
+/*
+     Flushes all pending output into the compressed 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
+   concatented gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ z_off_t  gzseek (gzFile file,
+                                   z_off_t offset, int whence);
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed 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.
+*/
+
+ int     gzrewind (gzFile file);
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ z_off_t     gztell (gzFile file);
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed 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)
+*/
+
+/*
+ z_off_t  gzoffset (gzFile file);
+
+     Returns the current offset in the file being read or written.  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.
+*/
+
+ int  gzeof (gzFile file);
+/*
+     Returns true (1) if the end-of-file indicator 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.
+*/
+
+ int  gzdirect (gzFile file);
+/*
+     Returns 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.)
+*/
+
+ int     gzclose (gzFile file);
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates 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.
+*/
+
+ int  gzclose_r (gzFile file);
+ int  gzclose_w (gzFile file);
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ const char *  gzerror (gzFile file, int *errnum);
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed 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.
+*/
+
+ void  gzclearerr (gzFile file);
+/*
+     Clears 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.
+*/
+
+uint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  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 CRC32 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();
+*/
+
+/*
+ uLong  adler32_combine (uLong adler1, uLong adler2,
+                                          z_off_t len2);
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
+   that the z_off_t type (like off_t) is a signed integer.  If len2 is
+   negative, the result has no meaning or utility.
+*/
+
+ uLong  crc32   (uLong crc, const Bytef *buf, uInt len);
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  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();
+*/
+
+/*
+ uLong  crc32_combine (uLong crc1, uLong crc2, z_off_t len2);
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ int  deflateInit_ (z_streamp strm, int level,
+                                     const char *version, int stream_size);
+ int  inflateInit_ (z_streamp strm,
+                                     const char *version, int stream_size);
+ int  deflateInit2_ (z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size);
+ int  inflateInit2_ (z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size);
+ int  inflateBackInit_ (z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size);
+#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))
+
+#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.
+ */
+ int  gzgetc_ (gzFile file);  /* backward compatibility */
+#ifdef Z_PREFIX_SET
+#  undef z_gzgetc
+#  define z_gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+#  define gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+    gzFile  gzopen64 (const char *, const char *);
+    z_off64_t  gzseek64 (gzFile, z_off64_t, int);
+    z_off64_t  gztell64 (gzFile);
+    z_off64_t  gzoffset64 (gzFile);
+    uLong  adler32_combine64 (uLong, uLong, z_off64_t);
+    uLong  crc32_combine64 (uLong, uLong, 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
+#  else
+#    define gzopen gzopen64
+#    define gzseek gzseek64
+#    define gztell gztell64
+#    define gzoffset gzoffset64
+#    define adler32_combine adler32_combine64
+#    define crc32_combine crc32_combine64
+#  endif
+#  ifndef Z_LARGE64
+      gzFile  gzopen64 (const char *, const char *);
+      z_off_t  gzseek64 (gzFile, z_off_t, int);
+      z_off_t  gztell64 (gzFile);
+      z_off_t  gzoffset64 (gzFile);
+      uLong  adler32_combine64 (uLong, uLong, z_off_t);
+      uLong  crc32_combine64 (uLong, uLong, z_off_t);
+#  endif
+#else
+    gzFile  gzopen (const char *, const char *);
+    z_off_t  gzseek (gzFile, z_off_t, int);
+    z_off_t  gztell (gzFile);
+    z_off_t  gzoffset (gzFile);
+    uLong  adler32_combine (uLong, uLong, z_off_t);
+    uLong  crc32_combine (uLong, uLong, z_off_t);
+#endif
+
+#else /* Z_SOLO */
+
+    uLong  adler32_combine (uLong, uLong, z_off_t);
+    uLong  crc32_combine (uLong, uLong, z_off_t);
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ const char   *  zError           (int);
+ int             inflateSyncPoint (z_streamp);
+
+const uint32_t * get_crc_table(void);
+ int             inflateUndermine (z_streamp, int);
+ int             inflateResetKeep (z_streamp);
+ int             deflateResetKeep (z_streamp);
+#if defined(_WIN32) && !defined(Z_SOLO)
+ gzFile          gzopen_w (const wchar_t *path,
+                                            const char *mode);
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+ int            gzvprintf Z_ARG((gzFile file,
+                                                  const char *format,
+                                                  va_list va));
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
+
+#endif
diff --git a/deps/libretro-common/include/compat/zlib/zutil.h b/deps/libretro-common/include/compat/zlib/zutil.h
new file mode 100644 (file)
index 0000000..bc67f5a
--- /dev/null
@@ -0,0 +1,253 @@
+#ifndef _COMPAT_ZUTIL_H
+#define _COMPAT_ZUTIL_H
+
+#ifdef WANT_ZLIB
+
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef 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 <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+
+#ifdef Z_SOLO
+   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* 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;
+
+extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
+/* (array size given to avoid silly warnings with Visual C++) */
+/* (array entry size given to avoid silly string cast warnings) */
+
+#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 <alloc.h>
+#      endif
+#    else /* MSC or DJGPP */
+#      include <malloc.h>
+#    endif
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  if defined(M_I86) && !defined(Z_SOLO)
+#    include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  ifndef Z_SOLO
+#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#      include <unix.h> /* for fdopen */
+#    else
+#      ifndef fdopen
+#        define fdopen(fd,mode) NULL /* No fdopen() */
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#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() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  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
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_WIN32) && \
+    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
+    uLong adler32_combine64 (uLong, uLong, z_off_t);
+    uLong crc32_combine64 (uLong, uLong, z_off_t);
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(pyr) || defined(Z_SOLO)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
+   int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
+   void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
+#endif
+
+/* Diagnostic functions */
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+
+#ifndef Z_SOLO
+   voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
+                                    unsigned size);
+   void ZLIB_INTERNAL zcfree  (voidpf opaque, voidpf ptr);
+#endif
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+/* Reverse the bytes in a 32-bit value */
+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+#endif /* ZUTIL_H */
+
+#else
+#include <zutil.h>
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/compat/zutil.h b/deps/libretro-common/include/compat/zutil.h
new file mode 100644 (file)
index 0000000..bce9a48
--- /dev/null
@@ -0,0 +1,253 @@
+#ifndef _COMPAT_ZUTIL_H
+#define _COMPAT_ZUTIL_H
+
+#ifdef WANT_ZLIB
+
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#ifdef HAVE_HIDDEN
+#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+#  define ZLIB_INTERNAL
+#endif
+
+#include <compat/zlib.h>
+
+#if defined(STDC) && !defined(Z_SOLO)
+#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+
+#ifdef Z_SOLO
+   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* 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;
+
+extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
+/* (array size given to avoid silly warnings with Visual C++) */
+/* (array entry size given to avoid silly string cast warnings) */
+
+#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 <alloc.h>
+#      endif
+#    else /* MSC or DJGPP */
+#      include <malloc.h>
+#    endif
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  if defined(M_I86) && !defined(Z_SOLO)
+#    include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  ifndef Z_SOLO
+#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#      include <unix.h> /* for fdopen */
+#    else
+#      ifndef fdopen
+#        define fdopen(fd,mode) NULL /* No fdopen() */
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#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() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  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
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_WIN32) && \
+    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
+    uLong adler32_combine64 (uLong, uLong, z_off_t);
+    uLong crc32_combine64 (uLong, uLong, z_off_t);
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(pyr) || defined(Z_SOLO)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
+   int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
+   void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
+#endif
+
+/* Diagnostic functions */
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+
+#ifndef Z_SOLO
+   voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
+                                    unsigned size);
+   void ZLIB_INTERNAL zcfree  (voidpf opaque, voidpf ptr);
+#endif
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+/* Reverse the bytes in a 32-bit value */
+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+#endif /* ZUTIL_H */
+
+#else
+#include <zutil.h>
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/defines/cocoa_defines.h b/deps/libretro-common/include/defines/cocoa_defines.h
new file mode 100644 (file)
index 0000000..1d94843
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 2010-2021 The RetroArch team\r
+ *\r
+ * ---------------------------------------------------------------------------------------\r
+ * The following license statement only applies to this file (cocoa_defines.h).\r
+ * ---------------------------------------------------------------------------------------\r
+ *\r
+ * Permission is hereby granted, free of charge,\r
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\r
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+#ifndef __COCOA_COMMON_DEFINES_H\r
+#define __COCOA_COMMON_DEFINES_H\r
+\r
+#include <AvailabilityMacros.h>\r
+\r
+#ifndef MAC_OS_X_VERSION_10_12\r
+#define MAC_OS_X_VERSION_10_12 101200\r
+#endif\r
+\r
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12\r
+#define HAS_MACOSX_10_12 0\r
+#define NSEventModifierFlagCommand NSCommandKeyMask\r
+#define NSEventModifierFlagControl NSControlKeyMask\r
+#define NSEventModifierFlagHelp NSHelpKeyMask\r
+#define NSEventModifierFlagNumericPad NSNumericPadKeyMask\r
+#define NSEventModifierFlagOption NSAlternateKeyMask\r
+#define NSEventModifierFlagShift NSShiftKeyMask\r
+#define NSCompositingOperationSourceOver NSCompositeSourceOver\r
+#define NSEventMaskApplicationDefined NSApplicationDefinedMask\r
+#define NSEventTypeApplicationDefined NSApplicationDefined\r
+#define NSEventTypeCursorUpdate NSCursorUpdate\r
+#define NSEventTypeMouseMoved NSMouseMoved\r
+#define NSEventTypeMouseEntered NSMouseEntered\r
+#define NSEventTypeMouseExited NSMouseExited\r
+#define NSEventTypeLeftMouseDown NSLeftMouseDown\r
+#define NSEventTypeRightMouseDown NSRightMouseDown\r
+#define NSEventTypeOtherMouseDown NSOtherMouseDown\r
+#define NSEventTypeLeftMouseUp NSLeftMouseUp\r
+#define NSEventTypeRightMouseUp NSRightMouseUp\r
+#define NSEventTypeOtherMouseUp NSOtherMouseUp\r
+#define NSEventTypeLeftMouseDragged NSLeftMouseDragged\r
+#define NSEventTypeRightMouseDragged NSRightMouseDragged\r
+#define NSEventTypeOtherMouseDragged NSOtherMouseDragged\r
+#define NSEventTypeScrollWheel NSScrollWheel\r
+#define NSEventTypeKeyDown NSKeyDown\r
+#define NSEventTypeKeyUp NSKeyUp\r
+#define NSEventTypeFlagsChanged NSFlagsChanged\r
+#define NSEventMaskAny NSAnyEventMask\r
+#define NSWindowStyleMaskBorderless NSBorderlessWindowMask\r
+#define NSWindowStyleMaskClosable NSClosableWindowMask\r
+#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask\r
+#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask\r
+#define NSWindowStyleMaskResizable NSResizableWindowMask\r
+#define NSWindowStyleMaskTitled NSTitledWindowMask\r
+#define NSAlertStyleCritical NSCriticalAlertStyle\r
+#define NSAlertStyleInformational NSInformationalAlertStyle\r
+#define NSAlertStyleWarning  NSWarningAlertStyle\r
+#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask\r
+#define NSControlSizeRegular NSRegularControlSize\r
+#else\r
+#define HAS_MACOSX_10_12 1\r
+#endif\r
+\r
+#endif\r
diff --git a/deps/libretro-common/include/defines/d3d_defines.h b/deps/libretro-common/include/defines/d3d_defines.h
new file mode 100644 (file)
index 0000000..a090f4c
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (d3d_defines.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 D3DVIDEO_DEFINES_H
+#define D3DVIDEO_DEFINES_H
+
+#if defined(DEBUG) || defined(_DEBUG)
+#define D3D_DEBUG_INFO
+#endif
+
+#if defined(HAVE_D3D9)
+/* Direct3D 9 */
+#if 0
+#include <d3d9.h>
+#endif
+
+#if 0
+#define LPDIRECT3D                     LPDIRECT3D9
+#define LPDIRECT3DDEVICE               LPDIRECT3DDEVICE9
+#define LPDIRECT3DTEXTURE              LPDIRECT3DTEXTURE9
+#define LPDIRECT3DCUBETEXTURE          LPDIRECT3DCUBETEXTURE9
+#define LPDIRECT3DVERTEXBUFFER         LPDIRECT3DVERTEXBUFFER9
+#define LPDIRECT3DVERTEXSHADER         LPDIRECT3DVERTEXSHADER9
+#define LPDIRECT3DPIXELSHADER          LPDIRECT3DPIXELSHADER9
+#define LPDIRECT3DSURFACE              LPDIRECT3DSURFACE9
+#define LPDIRECT3DVERTEXDECLARATION    LPDIRECT3DVERTEXDECLARATION9
+#define LPDIRECT3DVOLUMETEXTURE        LPDIRECT3DVOLUMETEXTURE9
+#define LPDIRECT3DRESOURCE             LPDIRECT3DRESOURCE9
+#define D3DVERTEXELEMENT               D3DVERTEXELEMENT9
+#define D3DVIEWPORT                    D3DVIEWPORT9
+#endif
+
+#ifndef D3DCREATE_SOFTWARE_VERTEXPROCESSING
+#define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0
+#endif
+
+#elif defined(HAVE_D3D8)
+#if 0
+#ifdef _XBOX
+#include <xtl.h>
+#else
+#include "../gfx/include/d3d8/d3d8.h"
+#endif
+#endif
+
+/* Direct3D 8 */
+#if 0
+#define LPDIRECT3D                     LPDIRECT3D8
+#define LPDIRECT3DDEVICE               LPDIRECT3DDEVICE8
+#define LPDIRECT3DTEXTURE              LPDIRECT3DTEXTURE8
+#define LPDIRECT3DCUBETEXTURE          LPDIRECT3DCUBETEXTURE8
+#define LPDIRECT3DVOLUMETEXTURE        LPDIRECT3DVOLUMETEXTURE8
+#define LPDIRECT3DVERTEXBUFFER         LPDIRECT3DVERTEXBUFFER8
+#define LPDIRECT3DVERTEXDECLARATION    (void*)
+#define LPDIRECT3DSURFACE              LPDIRECT3DSURFACE8
+#define LPDIRECT3DRESOURCE             LPDIRECT3DRESOURCE8
+#define D3DVERTEXELEMENT               D3DVERTEXELEMENT8
+#define D3DVIEWPORT                    D3DVIEWPORT8
+#endif
+
+#if !defined(D3DLOCK_NOSYSLOCK) && defined(_XBOX)
+#define D3DLOCK_NOSYSLOCK (0)
+#endif
+
+#if 0
+#define D3DSAMP_ADDRESSU D3DTSS_ADDRESSU
+#define D3DSAMP_ADDRESSV D3DTSS_ADDRESSV
+#define D3DSAMP_MAGFILTER D3DTSS_MAGFILTER
+#define D3DSAMP_MINFILTER D3DTSS_MINFILTER
+#endif
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/defines/gx_defines.h b/deps/libretro-common/include/defines/gx_defines.h
new file mode 100644 (file)
index 0000000..2b6b904
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (gx_defines.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _GX_DEFINES_H
+#define _GX_DEFINES_H
+
+#ifdef GEKKO
+
+#define SYSMEM1_SIZE 0x01800000
+
+#define _SHIFTL(v, s, w)       ((uint32_t) (((uint32_t)(v) & ((0x01 << (w)) - 1)) << (s)))
+#define _SHIFTR(v, s, w)       ((uint32_t)(((uint32_t)(v) >> (s)) & ((0x01 << (w)) - 1)))
+
+#define OSThread lwp_t
+#define OSCond lwpq_t
+#define OSThreadQueue lwpq_t
+
+#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
+#define OSLockMutex(mutex) LWP_MutexLock(mutex)
+#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
+#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)
+
+#define OSInitCond(cond) LWP_CondInit(cond)
+#define OSSignalCond(cond) LWP_ThreadSignal(cond)
+#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)
+
+#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
+#define OSCloseThreadQueue(queue) LWP_CloseQueue(queue)
+#define OSSleepThread(queue) LWP_ThreadSleep(queue)
+#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)
+
+#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)
+
+#define BLIT_LINE_16(off) \
+{ \
+   const uint32_t *tmp_src = src; \
+   uint32_t       *tmp_dst = dst; \
+   for (unsigned x = 0; x < width2 >> 1; x++, tmp_src += 2, tmp_dst += 8) \
+   { \
+      tmp_dst[ 0 + off] = BLIT_LINE_16_CONV(tmp_src[0]); \
+      tmp_dst[ 1 + off] = BLIT_LINE_16_CONV(tmp_src[1]); \
+   } \
+   src += tmp_pitch; \
+}
+
+#define BLIT_LINE_32(off) \
+{ \
+   const uint16_t *tmp_src = src; \
+   uint16_t       *tmp_dst = dst; \
+   for (unsigned x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \
+   { \
+      tmp_dst[  0 + off] = tmp_src[0] | 0xFF00; \
+      tmp_dst[ 16 + off] = tmp_src[1]; \
+      tmp_dst[  1 + off] = tmp_src[2] | 0xFF00; \
+      tmp_dst[ 17 + off] = tmp_src[3]; \
+      tmp_dst[  2 + off] = tmp_src[4] | 0xFF00; \
+      tmp_dst[ 18 + off] = tmp_src[5]; \
+      tmp_dst[  3 + off] = tmp_src[6] | 0xFF00; \
+      tmp_dst[ 19 + off] = tmp_src[7]; \
+   } \
+   src += tmp_pitch; \
+}
+
+#define CHUNK_FRAMES 64
+#define CHUNK_SIZE (CHUNK_FRAMES * sizeof(uint32_t))
+#define BLOCKS 16
+
+#define AIInit AUDIO_Init
+#define AIInitDMA AUDIO_InitDMA
+#define AIStartDMA AUDIO_StartDMA
+#define AIStopDMA AUDIO_StopDMA
+#define AIRegisterDMACallback AUDIO_RegisterDMACallback
+#define AISetDSPSampleRate AUDIO_SetDSPSampleRate
+
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/defines/ps3_defines.h b/deps/libretro-common/include/defines/ps3_defines.h
new file mode 100644 (file)
index 0000000..0a94d27
--- /dev/null
@@ -0,0 +1,952 @@
+/* Copyright (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (ps3_defines.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _PS3_DEFINES_H
+#define _PS3_DEFINES_H
+
+/*============================================================
+       AUDIO PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <audio/audio.h>
+#include <sys/thread.h>
+
+#include <sys/event_queue.h>
+#include <lv2/mutex.h>
+#include <lv2/cond.h>
+
+/*forward decl. for audioAddData */
+extern int audioAddData(uint32_t portNum, float *data,
+      uint32_t frames, float volume);
+
+#define PS3_SYS_NO_TIMEOUT 0
+#define param_attrib attrib
+
+#else
+#include <sdk_version.h>
+#include <cell/audio.h>
+#include <sys/event.h>
+#include <sys/synchronization.h>
+
+#define numChannels nChannel
+#define numBlocks nBlock
+#define param_attrib attr
+
+#define audioQuit cellAudioQuit 
+#define audioInit cellAudioInit
+#define audioPortStart cellAudioPortStart
+#define audioPortOpen cellAudioPortOpen
+#define audioPortClose cellAudioPortClose
+#define audioPortStop cellAudioPortStop
+#define audioPortParam CellAudioPortParam
+#define audioPortOpen cellAudioPortOpen
+#define audioAddData cellAudioAddData
+
+/* event queue functions */
+#define sysEventQueueReceive sys_event_queue_receive
+#define audioSetNotifyEventQueue cellAudioSetNotifyEventQueue
+#define audioRemoveNotifyEventQueue cellAudioRemoveNotifyEventQueue
+#define audioCreateNotifyEventQueue cellAudioCreateNotifyEventQueue
+
+#define sysLwCondCreate sys_lwcond_create
+#define sysLwCondDestroy sys_lwcond_destroy
+#define sysLwCondWait sys_lwcond_wait
+#define sysLwCondSignal sys_lwcond_signal
+
+#define sysLwMutexDestroy sys_lwmutex_destroy
+#define sysLwMutexLock sys_lwmutex_lock
+#define sysLwMutexUnlock sys_lwmutex_unlock
+#define sysLwMutexCreate sys_lwmutex_create
+
+#define AUDIO_BLOCK_SAMPLES CELL_AUDIO_BLOCK_SAMPLES
+#define SYSMODULE_NET CELL_SYSMODULE_NET
+#define PS3_SYS_NO_TIMEOUT SYS_NO_TIMEOUT
+
+#define sys_lwmutex_attr_t sys_lwmutex_attribute_t 
+#define sys_lwcond_attr_t sys_lwcond_attribute_t 
+#define sys_sem_t sys_semaphore_t
+
+#define sysGetSystemTime sys_time_get_system_time
+#define sysModuleLoad cellSysmoduleLoadModule
+#define sysModuleUnload cellSysmoduleUnloadModule
+
+#define netInitialize sys_net_initialize_network
+
+#endif
+
+/*============================================================
+       INPUT PAD PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <io/pad.h>
+#define CELL_PAD_CAPABILITY_SENSOR_MODE      4
+#define CELL_PAD_SETTING_SENSOR_ON           4
+#define CELL_PAD_STATUS_ASSIGN_CHANGES       2
+#define CELL_PAD_BTN_OFFSET_DIGITAL1         2
+#define CELL_PAD_BTN_OFFSET_DIGITAL2         3
+#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X   4
+#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y   5
+#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X    6
+#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y    7
+#define CELL_PAD_BTN_OFFSET_PRESS_RIGHT      8
+#define CELL_PAD_BTN_OFFSET_PRESS_LEFT       9
+#define CELL_PAD_BTN_OFFSET_PRESS_UP         10
+#define CELL_PAD_BTN_OFFSET_PRESS_DOWN       11
+#define CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE   12
+#define CELL_PAD_BTN_OFFSET_PRESS_CIRCLE     13
+#define CELL_PAD_BTN_OFFSET_PRESS_CROSS      14
+#define CELL_PAD_BTN_OFFSET_PRESS_SQUARE     15
+#define CELL_PAD_BTN_OFFSET_PRESS_L1         16
+#define CELL_PAD_BTN_OFFSET_PRESS_R1         17
+#define CELL_PAD_BTN_OFFSET_PRESS_L2         18
+#define CELL_PAD_BTN_OFFSET_PRESS_R2         19
+#define CELL_PAD_BTN_OFFSET_SENSOR_X         20
+#define CELL_PAD_BTN_OFFSET_SENSOR_Y         21
+#define CELL_PAD_BTN_OFFSET_SENSOR_Z         22
+#define CELL_PAD_BTN_OFFSET_SENSOR_G         23
+#define CELL_PAD_CTRL_LEFT          (128)
+#define CELL_PAD_CTRL_DOWN          (64)
+#define CELL_PAD_CTRL_RIGHT         (32)
+#define CELL_PAD_CTRL_UP            (16)
+#define CELL_PAD_CTRL_START         (8)
+#define CELL_PAD_CTRL_R3            (4)
+#define CELL_PAD_CTRL_L3            (2)
+#define CELL_PAD_CTRL_SELECT        (1)
+#define CELL_PAD_CTRL_SQUARE        (128)
+#define CELL_PAD_CTRL_CROSS         (64)
+#define CELL_PAD_CTRL_CIRCLE        (32)
+#define CELL_PAD_CTRL_TRIANGLE      (16)
+#define CELL_PAD_CTRL_R1            (8)
+#define CELL_PAD_CTRL_L1            (4)
+#define CELL_PAD_CTRL_R2            (2)
+#define CELL_PAD_CTRL_L2            (1)
+#define CELL_PAD_CTRL_LDD_PS        (1)
+#define CELL_PAD_STATUS_CONNECTED   (1)
+#define CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN
+#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CROSS  (1)
+#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CIRCLE (0)
+#define now_connect connected
+#define CellPadActParam padActParam
+#define cellPadSetPortSetting ioPadSetPortSetting
+#define cellSysutilGetSystemParamInt sysUtilGetSystemParamInt
+#define cellPadSetActDirect ioPadSetActDirect
+#define CellPadInfo2 padInfo2
+#define cellPadGetInfo2 ioPadGetInfo2
+#define CellPadData padData
+#define cellPadGetData ioPadGetData
+#define cellPadInit ioPadInit 
+#define cellPadEnd ioPadEnd
+#else
+#include <cell/pad.h>
+#define padInfo2 CellPadInfo2
+#define padData CellPadData
+#define ioPadGetInfo2 cellPadGetInfo2 
+#define ioPadGetData cellPadGetData
+#define ioPadInit cellPadInit
+#define ioPadEnd cellPadEnd
+#define ioPadSetPortSetting cellPadSetPortSetting 
+#endif
+
+/*============================================================
+       INPUT MOUSE PROTOTYPES
+============================================================ */
+
+#ifdef HAVE_MOUSE
+
+#ifdef __PSL1GHT__
+#include <io/mouse.h>
+
+/* define ps3 mouse structs */
+#define CellMouseInfo mouseInfo
+#define CellMouseData mouseData
+
+/* define all the ps3 mouse functions */
+#define cellMouseInit ioMouseInit
+#define cellMouseGetData ioMouseGetData
+#define cellMouseEnd ioMouseEnd
+#define cellMouseGetInfo ioMouseGetInfo
+
+/* PSL1GHT does not define these in its header */
+#define CELL_MOUSE_BUTTON_1 (UINT64_C(1) << 0) /* Button 1 */
+#define CELL_MOUSE_BUTTON_2 (UINT64_C(1) << 1) /* Button 2 */
+#define CELL_MOUSE_BUTTON_3 (UINT64_C(1) << 2) /* Button 3 */
+#define CELL_MOUSE_BUTTON_4 (UINT64_C(1) << 3) /* Button 4 */
+#define CELL_MOUSE_BUTTON_5 (UINT64_C(1) << 4) /* Button 5 */
+#define CELL_MOUSE_BUTTON_6 (UINT64_C(1) << 5) /* Button 6 */
+#define CELL_MOUSE_BUTTON_7 (UINT64_C(1) << 6) /* Button 7 */
+#define CELL_MOUSE_BUTTON_8 (UINT64_C(1) << 7) /* Button 8 */
+
+#else
+#include <cell/mouse.h>
+#define mouseInfo CellMouseInfo
+#define mouseData CellMouseData
+
+#define ioMouseInit cellMouseInit
+#define ioMouseGetData cellMouseGetData
+#define ioMouseEnd cellMouseEnd
+#define ioMouseGetInfo cellMouseGetInfo
+#endif
+
+#endif
+
+/*============================================================
+       INPUT KEYBOARD PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <io/kb.h>
+
+#define CELL_KB_RMODE_INPUTCHAR KB_RMODE_INPUTCHAR
+#define CELL_KB_CODETYPE_RAW    KB_CODETYPE_RAW
+
+#define cellKbData KbData
+#define cellKbInfo KbInfo
+
+#define cellKbSetCodeType ioKbSetCodeType
+#define cellKbSetReadMode ioKbSetReadMode
+#define cellKbInit ioKbInit
+#define cellKbGetInfo ioKbGetInfo
+#define cellKbRead ioKbRead
+#else
+#include <cell/keyboard.h>
+
+#define KB_RMODE_INPUTCHAR CELL_KB_RMODE_INPUTCHAR
+#define KB_CODETYPE_RAW    CELL_KB_CODETYPE_RAW
+
+#define KbInfo cellKbInfo
+
+#define ioKbSetCodeType cellKbSetCodeType
+#define ioKbSetReadMode cellKbSetReadMode
+#define ioKbInit cellKbInit
+#define ioKbGetInfo cellKbGetInfo
+#define ioKbRead cellKbRead
+
+/* Keyboard RAWDAT Key code (can't be converted to ASCII codes) */
+#define KB_RAWKEY_NO_EVENT                     0x00
+#define KB_RAWKEY_E_ROLLOVER                   0x01
+#define KB_RAWKEY_E_POSTFAIL                   0x02
+#define KB_RAWKEY_E_UNDEF                      0x03
+#define KB_RAWKEY_ESCAPE                       0x29
+#define KB_RAWKEY_106_KANJI                    0x35    /* The half-width/full width Kanji key code */
+#define KB_RAWKEY_CAPS_LOCK                    0x39
+#define KB_RAWKEY_F1                           0x3a
+#define KB_RAWKEY_F2                           0x3b
+#define KB_RAWKEY_F3                           0x3c
+#define KB_RAWKEY_F4                           0x3d
+#define KB_RAWKEY_F5                           0x3e
+#define KB_RAWKEY_F6                           0x3f
+#define KB_RAWKEY_F7                           0x40
+#define KB_RAWKEY_F8                           0x41
+#define KB_RAWKEY_F9                           0x42
+#define KB_RAWKEY_F10                          0x43
+#define KB_RAWKEY_F11                          0x44
+#define KB_RAWKEY_F12                          0x45
+#define KB_RAWKEY_PRINTSCREEN                  0x46
+#define KB_RAWKEY_SCROLL_LOCK                  0x47
+#define KB_RAWKEY_PAUSE                                0x48
+#define KB_RAWKEY_INSERT                       0x49
+#define KB_RAWKEY_HOME                         0x4a
+#define KB_RAWKEY_PAGE_UP                      0x4b
+#define KB_RAWKEY_DELETE                       0x4c
+#define KB_RAWKEY_END                          0x4d
+#define KB_RAWKEY_PAGE_DOWN                    0x4e
+#define KB_RAWKEY_RIGHT_ARROW                  0x4f
+#define KB_RAWKEY_LEFT_ARROW                   0x50
+#define KB_RAWKEY_DOWN_ARROW                   0x51
+#define KB_RAWKEY_UP_ARROW                     0x52
+#define KB_RAWKEY_NUM_LOCK                     0x53
+#define KB_RAWKEY_APPLICATION                  0x65    /* Application key code */
+#define KB_RAWKEY_KANA                         0x88    /* Katakana/Hiragana/Romaji key code */
+#define KB_RAWKEY_HENKAN                       0x8a    /* Conversion key code */
+#define KB_RAWKEY_MUHENKAN                     0x8b    /* No Conversion key code */
+
+/* Keyboard RAW Key Code definition */
+#define KB_RAWKEY_A                            0x04
+#define KB_RAWKEY_B                            0x05
+#define KB_RAWKEY_C                            0x06
+#define KB_RAWKEY_D                            0x07
+#define KB_RAWKEY_E                            0x08
+#define KB_RAWKEY_F                            0x09
+#define KB_RAWKEY_G                            0x0A
+#define KB_RAWKEY_H                            0x0B
+#define KB_RAWKEY_I                            0x0C
+#define KB_RAWKEY_J                            0x0D
+#define KB_RAWKEY_K                            0x0E
+#define KB_RAWKEY_L                            0x0F
+#define KB_RAWKEY_M                            0x10
+#define KB_RAWKEY_N                            0x11
+#define KB_RAWKEY_O                            0x12
+#define KB_RAWKEY_P                            0x13
+#define KB_RAWKEY_Q                            0x14
+#define KB_RAWKEY_R                            0x15
+#define KB_RAWKEY_S                            0x16
+#define KB_RAWKEY_T                            0x17
+#define KB_RAWKEY_U                            0x18
+#define KB_RAWKEY_V                            0x19
+#define KB_RAWKEY_W                            0x1A
+#define KB_RAWKEY_X                            0x1B
+#define KB_RAWKEY_Y                            0x1C
+#define KB_RAWKEY_Z                            0x1D
+#define KB_RAWKEY_1                            0x1E
+#define KB_RAWKEY_2                            0x1F
+#define KB_RAWKEY_3                            0x20
+#define KB_RAWKEY_4                            0x21
+#define KB_RAWKEY_5                            0x22
+#define KB_RAWKEY_6                            0x23
+#define KB_RAWKEY_7                            0x24
+#define KB_RAWKEY_8                            0x25
+#define KB_RAWKEY_9                            0x26
+#define KB_RAWKEY_0                            0x27
+#define KB_RAWKEY_ENTER                                0x28
+#define KB_RAWKEY_ESC                          0x29
+#define KB_RAWKEY_BS                           0x2A
+#define KB_RAWKEY_TAB                          0x2B
+#define KB_RAWKEY_SPACE                                0x2C
+#define KB_RAWKEY_MINUS                                0x2D
+#define KB_RAWKEY_EQUAL_101                    0x2E    /* = and + */
+#define KB_RAWKEY_ACCENT_CIRCONFLEX_106        0x2E    /* ^ and ~ */
+#define KB_RAWKEY_LEFT_BRACKET_101             0x2F    /* [ */
+#define KB_RAWKEY_ATMARK_106                   0x2F    /* @ */
+#define KB_RAWKEY_RIGHT_BRACKET_101            0x30    /* ] */
+#define KB_RAWKEY_LEFT_BRACKET_106             0x30    /* [ */
+#define KB_RAWKEY_BACKSLASH_101                        0x31    /* \ and | */
+#define KB_RAWKEY_RIGHT_BRACKET_106            0x32    /* ] */
+#define KB_RAWKEY_SEMICOLON                    0x33    /* ; */
+#define KB_RAWKEY_QUOTATION_101                        0x34    /* ' and " */
+#define KB_RAWKEY_COLON_106                    0x34    /* : and * */
+#define KB_RAWKEY_COMMA                                0x36
+#define KB_RAWKEY_PERIOD                       0x37
+#define KB_RAWKEY_SLASH                                0x38
+#define KB_RAWKEY_CAPS_LOCK                    0x39
+#define KB_RAWKEY_KPAD_NUMLOCK                 0x53
+#define KB_RAWKEY_KPAD_SLASH                   0x54
+#define KB_RAWKEY_KPAD_ASTERISK                        0x55
+#define KB_RAWKEY_KPAD_MINUS                   0x56
+#define KB_RAWKEY_KPAD_PLUS                    0x57
+#define KB_RAWKEY_KPAD_ENTER                   0x58
+#define KB_RAWKEY_KPAD_1                       0x59
+#define KB_RAWKEY_KPAD_2                       0x5A
+#define KB_RAWKEY_KPAD_3                       0x5B
+#define KB_RAWKEY_KPAD_4                       0x5C
+#define KB_RAWKEY_KPAD_5                       0x5D
+#define KB_RAWKEY_KPAD_6                       0x5E
+#define KB_RAWKEY_KPAD_7                       0x5F
+#define KB_RAWKEY_KPAD_8                       0x60
+#define KB_RAWKEY_KPAD_9                       0x61
+#define KB_RAWKEY_KPAD_0                       0x62
+#define KB_RAWKEY_KPAD_PERIOD                  0x63
+#define KB_RAWKEY_BACKSLASH_106                        0x87
+#define KB_RAWKEY_YEN_106                      0x89
+
+#define KB_CODETYPE_RAW CELL_KB_CODETYPE_RAW
+
+/*! \brief Keyboard Led State. */
+typedef struct KbLed
+{
+       union
+   {
+      uint32_t leds;
+      struct
+      {
+         uint32_t reserved        : 27;        /*!< \brief Reserved MSB */
+         uint32_t kana            : 1; /*!< \brief LED Kana 0:OFF 1:ON Bit4 */
+         uint32_t compose              : 1;    /*!< \brief LED Compose 0:OFF 1:ON Bit3 */
+         uint32_t scroll_lock  : 1;    /*!< \brief LED Scroll Lock 0:OFF 1:ON Bit2 */
+         uint32_t caps_lock    : 1;    /*!< \brief LED Caps Lock 0:OFF 1:ON Bit1 */
+         uint32_t num_lock        : 1; /*!< \brief LED Num Lock 0:OFF 1:ON Bit0 LSB */
+      }_KbLedS;
+   }_KbLedU;
+} KbLed;
+
+
+/*! \brief Keyboard Modifier Key State. */
+typedef struct KbMkey
+{
+   union
+   {
+      uint32_t mkeys;
+      struct
+      {
+         uint32_t reserved        : 24;        /*!< \brief Reserved MSB */
+         uint32_t r_win                   : 1; /*!< \brief Modifier Key Right WIN 0:OFF 1:ON Bit7 */
+         uint32_t r_alt                   : 1; /*!< \brief Modifier Key Right ALT 0:OFF 1:ON Bit6 */
+         uint32_t r_shift              : 1;    /*!< \brief Modifier Key Right SHIFT 0:OFF 1:ON Bit5 */         
+         uint32_t r_ctrl               : 1;    /*!< \brief Modifier Key Right CTRL 0:OFF 1:ON Bit4 */
+         uint32_t l_win                   : 1; /*!< \brief Modifier Key Left WIN 0:OFF 1:ON Bit3 */
+         uint32_t l_alt                   : 1; /*!< \brief Modifier Key Left ALT 0:OFF 1:ON Bit2 */
+         uint32_t l_shift              : 1;    /*!< \brief Modifier Key Left SHIFT 0:OFF 1:ON Bit1 */
+         uint32_t l_ctrl               : 1;    /*!< \brief Modifier Key Left CTRL 0:OFF 1:ON Bit0 LSB */
+         /* For Macintosh Keyboard ALT & WIN correspond respectively to OPTION & APPLE keys */
+      }_KbMkeyS;
+   }_KbMkeyU;
+} KbMkey;
+
+/*! \brief Keyboard input data data structure. */
+typedef struct KbData
+{
+       KbLed led;                                      /*!< \brief Keyboard Led State */
+       KbMkey mkey;                            /*!< \brief Keyboard Modifier Key State */
+       int32_t  nb_keycode;                            /*!< \brief Number of key codes (0 equal no data) */
+       uint16_t keycode[MAX_KEYCODES]; /*!< \brief Keycode values */
+} KbData;
+#endif
+
+/*============================================================
+       OSK PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <sysutil/osk.h>
+/* define all the OSK functions */
+#define pOskLoadAsync oskLoadAsync
+#define pOskSetLayoutMode oskSetLayoutMode
+#define pOskSetKeyLayoutOption oskSetKeyLayoutOption
+#define pOskGetSize oskGetSize
+#define pOskDisableDimmer oskDisableDimmer
+#define pOskAbort oskAbort
+#define pOskUnloadAsync oskUnloadAsync
+
+/* define OSK structs / types */
+#define sys_memory_container_t sys_mem_container_t
+#define CellOskDialogPoint oskPoint
+#define CellOskDialogInputFieldInfo oskInputFieldInfo
+#define CellOskDialogCallbackReturnParam oskCallbackReturnParam
+#define CellOskDialogParam oskParam
+
+#define osk_allowed_panels allowedPanels
+#define osk_prohibit_flags prohibitFlags
+
+#define osk_inputfield_message message
+#define osk_inputfield_starttext startText
+#define osk_inputfield_max_length maxLength
+#define osk_callback_return_param res
+#define osk_callback_num_chars len
+#define osk_callback_return_string str
+
+/* define the OSK defines */
+#define CELL_OSKDIALOG_10KEY_PANEL OSK_10KEY_PANEL
+#define CELL_OSKDIALOG_FULLKEY_PANEL OSK_FULLKEY_PANEL
+#define CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_CENTER OSK_LAYOUTMODE_HORIZONTAL_ALIGN_CENTER
+#define CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_TOP OSK_LAYOUTMODE_VERTICAL_ALIGN_TOP
+#define CELL_OSKDIALOG_PANELMODE_NUMERAL OSK_PANEL_TYPE_NUMERAL
+#define CELL_OSKDIALOG_PANELMODE_NUMERAL_FULL_WIDTH OSK_PANEL_TYPE_NUMERAL_FULL_WIDTH
+#define CELL_OSKDIALOG_PANELMODE_ALPHABET OSK_PANEL_TYPE_ALPHABET
+#define CELL_OSKDIALOG_PANELMODE_ENGLISH OSK_PANEL_TYPE_ENGLISH
+#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK (0)
+#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED (1)
+#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT (2)
+#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT (3)
+#define CELL_OSKDIALOG_STRING_SIZE (512)
+#else
+#include <sysutil/sysutil_oskdialog.h>
+/* define all the OSK functions */
+#define pOskLoadAsync cellOskDialogLoadAsync
+#define pOskSetLayoutMode cellOskDialogSetLayoutMode
+#define pOskSetKeyLayoutOption cellOskDialogSetKeyLayoutOption
+#define pOskGetSize cellOskDialogGetSize
+#define pOskDisableDimmer cellOskDialogDisableDimmer
+#define pOskAbort cellOskDialogAbort
+#define pOskUnloadAsync cellOskDialogUnloadAsync
+
+/* define OSK structs / types */
+#define osk_allowed_panels allowOskPanelFlg
+#define osk_prohibit_flags prohibitFlgs
+#define osk_inputfield_message message
+#define osk_inputfield_starttext init_text
+#define osk_inputfield_max_length limit_length
+#define osk_callback_return_param result
+#define osk_callback_num_chars numCharsResultString
+#define osk_callback_return_string pResultString
+#endif
+
+/*============================================================
+       JPEG/PNG DECODING/ENCODING PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+
+#define spu_enable enable
+#define stream_select stream
+#define color_alpha alpha
+#define color_space space
+#define output_mode mode
+#define output_bytes_per_line bytes_per_line
+#define output_width width
+#define output_height height
+
+#define CELL_OK 0
+#define PTR_NULL 0
+
+#else
+/* define the JPEG/PNG struct member names */
+#define spu_enable spuThreadEnable
+#define ppu_prio ppuThreadPriority
+#define spu_prio spuThreadPriority
+#define malloc_func cbCtrlMallocFunc
+#define malloc_arg cbCtrlMallocArg
+#define free_func cbCtrlFreeFunc
+#define free_arg cbCtrlFreeArg
+#define stream_select srcSelect
+#define file_name fileName
+#define file_offset fileOffset
+#define file_size fileSize
+#define stream_ptr streamPtr
+#define stream_size streamSize
+#define down_scale downScale
+#define color_alpha outputColorAlpha
+#define color_space outputColorSpace
+#define cmd_ptr commandPtr
+#define quality method
+#define output_mode outputMode
+#define output_bytes_per_line outputBytesPerLine
+#define output_width outputWidth
+#define output_height outputHeight
+#define bit_depth outputBitDepth
+#define pack_flag outputPackFlag
+#define alpha_select outputAlphaSelect
+
+#define PTR_NULL NULL
+
+#endif
+
+/*============================================================
+       TIMER PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#define sys_timer_usleep usleep
+#endif
+
+/*============================================================
+       THREADING PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <sys/thread.h>
+
+/* FIXME - not sure if this is correct -> FIXED! 1 and not 0 */
+#define SYS_THREAD_CREATE_JOINABLE THREAD_JOINABLE
+
+#else
+#include <sys/ppu_thread.h>
+
+#define SYS_PROCESS_SPAWN_STACK_SIZE_1M SYS_PROCESS_PRIMARY_STACK_SIZE_1M 
+#define SYS_THREAD_CREATE_JOINABLE SYS_PPU_THREAD_CREATE_JOINABLE
+
+#define sysThreadCreate sys_ppu_thread_create 
+#define sysThreadJoin sys_ppu_thread_join 
+#define sysThreadExit sys_ppu_thread_exit 
+
+#define sysProcessExit sys_process_exit 
+#define sysProcessExitSpawn2 sys_game_process_exitspawn 
+
+#endif
+
+/*============================================================
+       MEMORY PROTOTYPES
+============================================================ */
+
+#ifndef __PSL1GHT__
+#define sysMemContainerCreate sys_memory_container_create 
+#define sysMemContainerDestroy sys_memory_container_destroy 
+#endif
+
+/*============================================================
+       RSX PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <sysutil/video.h>
+#define CELL_GCM_FALSE GCM_FALSE
+#define CELL_GCM_TRUE GCM_TRUE
+
+#define CELL_GCM_ONE GCM_ONE
+#define CELL_GCM_ZERO GCM_ZERO
+#define CELL_GCM_ALWAYS GCM_ALWAYS
+
+#define CELL_GCM_LOCATION_LOCAL GCM_LOCATION_RSX
+#define CELL_GCM_LOCATION_MAIN GCM_LOCATION_CELL
+
+#define CELL_GCM_MAX_RT_DIMENSION (4096)
+
+#define CELL_GCM_TEXTURE_LINEAR_NEAREST GCM_TEXTURE_LINEAR_MIPMAP_NEAREST
+#define CELL_GCM_TEXTURE_LINEAR_LINEAR GCM_TEXTURE_LINEAR_MIPMAP_LINEAR
+#define CELL_GCM_TEXTURE_NEAREST_LINEAR GCM_TEXTURE_NEAREST_MIPMAP_LINEAR
+#define CELL_GCM_TEXTURE_NEAREST_NEAREST GCM_TEXTURE_NEAREST_MIPMAP_NEAREST
+#define CELL_GCM_TEXTURE_NEAREST GCM_TEXTURE_NEAREST
+#define CELL_GCM_TEXTURE_LINEAR GCM_TEXTURE_LINEAR
+
+#define CELL_GCM_TEXTURE_A8R8G8B8 GCM_TEXTURE_FORMAT_A8R8G8B8
+#define CELL_GCM_TEXTURE_R5G6B5 GCM_TEXTURE_FORMAT_R5G6B5
+#define CELL_GCM_TEXTURE_A1R5G5B5 GCM_TEXTURE_FORMAT_A1R5G5B5
+
+#define CELL_GCM_TEXTURE_CLAMP_TO_EDGE GCM_TEXTURE_CLAMP_TO_EDGE
+
+#define CELL_GCM_TEXTURE_MAX_ANISO_1 GCM_TEXTURE_MAX_ANISO_1
+#define CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX GCM_TEXTURE_CONVOLUTION_QUINCUNX
+#define CELL_GCM_TEXTURE_ZFUNC_NEVER GCM_TEXTURE_ZFUNC_NEVER
+
+#define CELL_GCM_DISPLAY_HSYNC GCM_FLIP_HSYNC
+#define CELL_GCM_DISPLAY_VSYNC GCM_FLIP_VSYNC
+
+#define CELL_GCM_CLEAR_R GCM_CLEAR_R
+#define CELL_GCM_CLEAR_G GCM_CLEAR_G
+#define CELL_GCM_CLEAR_B GCM_CLEAR_B
+#define CELL_GCM_CLEAR_A GCM_CLEAR_A
+
+#define CELL_GCM_FUNC_ADD GCM_FUNC_ADD
+
+#define CELL_GCM_SMOOTH        (0x1D01)
+#define CELL_GCM_DEBUG_LEVEL2 2
+
+#define CELL_GCM_COMPMODE_DISABLED 0
+
+#define CELL_GCM_TRANSFER_LOCAL_TO_LOCAL 0
+
+#define CELL_GCM_TEXTURE_REMAP_ORDER_XYXY (0)
+#define CELL_GCM_TEXTURE_REMAP_ORDER_XXXY (1)
+
+#define CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL (0)
+
+#define CELL_GCM_TEXTURE_REMAP_FROM_A (0)
+#define CELL_GCM_TEXTURE_REMAP_FROM_R (1)
+#define CELL_GCM_TEXTURE_REMAP_FROM_G (2)
+#define CELL_GCM_TEXTURE_REMAP_FROM_B (3)
+
+#define CELL_GCM_TEXTURE_REMAP_ZERO (0)
+#define CELL_GCM_TEXTURE_REMAP_ONE (1)
+#define CELL_GCM_TEXTURE_REMAP_REMAP (2)
+
+#define CELL_GCM_MAX_TEXIMAGE_COUNT (16)
+
+#define CELL_GCM_TEXTURE_WRAP (1)
+
+#define CELL_GCM_TEXTURE_NR (0x00)
+#define CELL_GCM_TEXTURE_LN (0x20)
+
+#define CELL_GCM_TEXTURE_B8 (0x81)
+
+#define CELL_RESC_720x480 RESC_720x480
+#define CELL_RESC_720x576 RESC_720x576
+#define CELL_RESC_1280x720 RESC_1280x720
+#define CELL_RESC_1920x1080 RESC_1920x1080
+
+#define CELL_RESC_FULLSCREEN RESC_FULLSCREEN
+#define CELL_RESC_PANSCAN RESC_PANSCAN
+#define CELL_RESC_LETTERBOX RESC_LETTERBOX
+#define CELL_RESC_CONSTANT_VRAM RESC_CONSTANT_VRAM
+#define CELL_RESC_MINIMUM_GPU_LOAD RESC_MINIMUM_GPU_LOAD
+
+#define CELL_RESC_PAL_50 RESC_PAL_50
+#define CELL_RESC_PAL_60_DROP RESC_PAL_60_DROP
+#define CELL_RESC_PAL_60_INTERPOLATE RESC_PAL_60_INTERPOLATE
+#define CELL_RESC_PAL_60_INTERPOLATE_30_DROP RESC_PAL_60_INTERPOLATE_30_DROP
+#define CELL_RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE
+
+#define CELL_RESC_INTERLACE_FILTER RESC_INTERLACE_FILTER
+#define CELL_RESC_NORMAL_BILINEAR RESC_NORMAL_BILINEAR
+
+#define CELL_RESC_ELEMENT_HALF RESC_ELEMENT_HALF
+
+#define CELL_VIDEO_OUT_ASPECT_AUTO VIDEO_ASPECT_AUTO
+#define CELL_VIDEO_OUT_ASPECT_4_3 VIDEO_ASPECT_4_3
+#define CELL_VIDEO_OUT_ASPECT_16_9 VIDEO_ASPECT_16_9
+
+#define CELL_VIDEO_OUT_RESOLUTION_480 VIDEO_RESOLUTION_480
+#define CELL_VIDEO_OUT_RESOLUTION_576 VIDEO_RESOLUTION_576
+#define CELL_VIDEO_OUT_RESOLUTION_720 VIDEO_RESOLUTION_720
+#define CELL_VIDEO_OUT_RESOLUTION_1080 VIDEO_RESOLUTION_1080
+#define CELL_VIDEO_OUT_RESOLUTION_960x1080 VIDEO_RESOLUTION_960x1080
+#define CELL_VIDEO_OUT_RESOLUTION_1280x1080 VIDEO_RESOLUTION_1280x1080
+#define CELL_VIDEO_OUT_RESOLUTION_1440x1080 VIDEO_RESOLUTION_1440x1080
+#define CELL_VIDEO_OUT_RESOLUTION_1600x1080 VIDEO_RESOLUTION_1600x1080
+
+#define CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE VIDEO_SCANMODE_PROGRESSIVE
+
+#define CELL_VIDEO_OUT_PRIMARY VIDEO_PRIMARY
+
+#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8 VIDEO_BUFFER_FORMAT_XRGB
+#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT VIDEO_BUFFER_FORMAT_FLOAT
+
+#define CellGcmSurface gcmSurface
+#define CellGcmTexture gcmTexture
+#define CellGcmContextData _gcmCtxData
+#define CellGcmConfig gcmConfiguration
+#define CellVideoOutConfiguration videoConfiguration
+#define CellVideoOutResolution videoResolution
+#define CellVideoOutState videoState
+
+#define CellRescInitConfig rescInitConfig
+#define CellRescSrc rescSrc
+#define CellRescBufferMode rescBufferMode
+
+#define resolutionId resolution
+#define memoryFrequency memoryFreq
+#define coreFrequency coreFreq
+
+#define cellGcmFinish rsxFinish
+
+#define cellGcmGetFlipStatus gcmGetFlipStatus
+#define cellGcmResetFlipStatus gcmResetFlipStatus
+#define cellGcmSetWaitFlip gcmSetWaitFlip
+#define cellGcmSetDebugOutputLevel gcmSetDebugOutputLevel
+#define cellGcmSetDisplayBuffer gcmSetDisplayBuffer
+#define cellGcmSetGraphicsHandler gcmSetGraphicsHandler
+#define cellGcmSetFlipHandler gcmSetFlipHandler
+#define cellGcmSetVBlankHandler gcmSetVBlankHandler
+#define cellGcmGetConfiguration gcmGetConfiguration
+#define cellGcmSetJumpCommand rsxSetJumpCommand
+#define cellGcmFlush rsxFlushBuffer
+#define cellGcmSetFlipMode gcmSetFlipMode
+#define cellGcmSetFlip gcmSetFlip
+#define cellGcmGetLabelAddress gcmGetLabelAddress
+#define cellGcmUnbindTile gcmUnbindTile
+#define cellGcmBindTile gcmBindTile
+#define cellGcmSetTileInfo gcmSetTileInfo
+#define cellGcmAddressToOffset gcmAddressToOffset
+
+#define cellRescCreateInterlaceTable rescCreateInterlaceTable
+#define cellRescSetDisplayMode rescSetDisplayMode
+#define cellRescGetNumColorBuffers rescGetNumColorBuffers
+#define cellRescGetBufferSize rescGetBufferSize
+#define cellRescSetBufferAddress rescSetBufferAddress
+#define cellRescGetFlipStatus rescGetFlipStatus
+#define cellRescResetFlipStatus rescResetFlipStatus
+#define cellRescSetConvertAndFlip rescSetConvertAndFlip
+#define cellRescSetVBlankHandler rescSetVBlankHandler
+#define cellRescSetFlipHandler rescSetFlipHandler
+#define cellRescAdjustAspectRatio rescAdjustAspectRatio
+#define cellRescSetWaitFlip rescSetWaitFlip
+#define cellRescSetSrc rescSetSrc
+#define cellRescInit rescInit
+#define cellRescExit rescExit
+
+#define cellVideoOutConfigure videoConfigure
+#define cellVideoOutGetState videoGetState
+#define cellVideoOutGetResolution videoGetResolution
+#define cellVideoOutGetResolutionAvailability videoGetResolutionAvailability
+
+#define cellGcmSetViewportInline rsxSetViewport
+#define cellGcmSetReferenceCommandInline rsxSetReferenceCommand
+#define cellGcmSetBlendEquationInline rsxSetBlendEquation
+#define cellGcmSetWriteBackEndLabelInline rsxSetWriteBackendLabel
+#define cellGcmSetWaitLabelInline rsxSetWaitLabel
+#define cellGcmSetDepthTestEnableInline rsxSetDepthTestEnable
+#define cellGcmSetScissorInline rsxSetScissor
+#define cellGcmSetBlendEnableInline rsxSetBlendEnable
+#define cellGcmSetClearColorInline rsxSetClearColor
+#define cellGcmSetBlendFuncInline rsxSetBlendFunc
+#define cellGcmSetBlendColorInline rsxSetBlendColor
+#define cellGcmSetTextureFilterInline rsxTextureFilter
+#define cellGcmSetTextureControlInline rsxTextureControl
+#define cellGcmSetCullFaceEnableInline rsxSetCullFaceEnable
+#define cellGcmSetShadeModeInline rsxSetShadeModel
+#define cellGcmSetTransferImage rsxSetTransferImage
+#define cellGcmSetBlendColor rsxSetBlendColor
+#define cellGcmSetBlendEquation rsxSetBlendEquation
+#define cellGcmSetBlendFunc rsxSetBlendFunc
+#define cellGcmSetClearColor rsxSetClearColor
+#define cellGcmSetScissor rsxSetScissor
+#define celGcmSetInvalidateVertexCache(fifo) rsxInvalidateTextureCache(fifo, GCM_INVALIDATE_VERTEX_TEXTURE)
+#else
+#define cellGcmSetTransferImage cellGcmSetTransferImageInline
+#define celGcmSetInvalidateVertexCache cellGcmSetInvalidateVertexCacheInline
+#define rsxInit cellGcmInit
+#define rsxInvalidateTextureCache(a, b) cellGcmSetInvalidateVertexCache(a)
+#define rsxTextureControl cellGcmSetTextureControlInline
+#define rsxSetBlendEnable cellGcmSetBlendEnableInline 
+#endif
+
+/*============================================================
+       NETWORK PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <net/netctl.h>
+
+#define cellNetCtlInit netCtlInit
+#define cellNetCtlGetState netCtlGetState
+#define cellNetCtlTerm netCtlTerm
+
+#define CELL_NET_CTL_STATE_IPObtained NET_CTL_STATE_IPObtained
+#else
+#define netCtlInit cellNetCtlInit
+#define netCtlGetState cellNetCtlGetState
+#define netCtlTerm cellNetCtlTerm
+#define NET_CTL_STATE_IPObtained CELL_NET_CTL_STATE_IPObtained
+#endif
+
+/*============================================================
+       NET PROTOTYPES
+============================================================ */
+
+#if defined(HAVE_NETWORKING)
+#ifdef __PSL1GHT__
+#include <net/net.h>
+
+#define socketselect select
+#define socketclose close
+
+#define sys_net_initialize_network netInitialize
+#define sys_net_finalize_network netFinalizeNetwork
+#else
+#include <netex/net.h>
+#include <np.h>
+#include <np/drm.h>
+
+#define netInitialize sys_net_initialize_network
+#define netFinalizeNetwork sys_net_finalize_network
+#endif
+#endif
+
+/*============================================================
+       SYSUTIL PROTOTYPES
+============================================================ */
+
+#ifdef __PSL1GHT__
+#include <sysutil/game.h>
+#define CellGameContentSize sysGameContentSize
+#define cellGameContentPermit sysGameContentPermit
+#define cellGameBootCheck sysGameBootCheck
+
+#define CELL_GAME_ATTRIBUTE_APP_HOME   (UINT64_C(1) <<1) /* boot from / app_home/PS3_GAME */
+#define CELL_GAME_DIRNAME_SIZE                 32
+
+#define CELL_GAME_GAMETYPE_SYS         0
+#define CELL_GAME_GAMETYPE_DISC                1
+#define CELL_GAME_GAMETYPE_HDD         2
+#define CELL_GAME_GAMETYPE_GAMEDATA    3
+#define CELL_GAME_GAMETYPE_HOME                4
+
+#endif
+
+#if defined(HAVE_SYSUTILS)
+#ifdef __PSL1GHT__
+#include <sysutil/sysutil.h>
+
+#define CELL_SYSUTIL_REQUEST_EXITGAME SYSUTIL_EXIT_GAME
+
+#define cellSysutilRegisterCallback sysUtilRegisterCallback
+#define cellSysutilCheckCallback sysUtilCheckCallback
+#else
+#include <sysutil/sysutil_screenshot.h>
+#include <sysutil/sysutil_common.h>
+#include <sysutil/sysutil_gamecontent.h>
+#endif
+#endif
+
+#if(CELL_SDK_VERSION > 0x340000)
+#include <sysutil/sysutil_bgmplayback.h>
+#endif
+
+/*============================================================
+       SYSMODULE PROTOTYPES
+============================================================ */
+
+#if defined(HAVE_SYSMODULES)
+#ifdef __PSL1GHT__
+#include <sysmodule/sysmodule.h>
+
+#define CELL_SYSMODULE_IO SYSMODULE_IO
+#define CELL_SYSMODULE_FS SYSMODULE_FS
+#define CELL_SYSMODULE_NET SYSMODULE_NET
+#define CELL_SYSMODULE_SYSUTIL_NP SYSMODULE_SYSUTIL_NP
+#define CELL_SYSMODULE_JPGDEC SYSMODULE_JPGDEC
+#define CELL_SYSMODULE_PNGDEC SYSMODULE_PNGDEC
+#define CELL_SYSMODULE_FONT SYSMODULE_FONT
+#define CELL_SYSMODULE_FREETYPE SYSMODULE_FREETYPE
+#define CELL_SYSMODULE_FONTFT SYSMODULE_FONTFT
+
+#define cellSysmoduleLoadModule sysModuleLoad
+#define cellSysmoduleUnloadModule sysModuleUnload
+
+#else
+#include <cell/sysmodule.h>
+
+#define sysModuleLoad cellSysmoduleLoadModule
+#define sysModuleUnload cellSysmoduleUnloadModule
+#define SYSMODULE_NET CELL_SYSMODULE_NET
+#endif
+#endif
+
+/*============================================================
+       FS PROTOTYPES
+============================================================ */
+#define FS_SUCCEEDED 0
+#define FS_TYPE_DIR 1
+#ifdef __PSL1GHT__
+#include <lv2/sysfs.h>
+#ifndef O_RDONLY
+#define O_RDONLY SYS_O_RDONLY
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY SYS_O_WRONLY
+#endif
+#ifndef O_CREAT
+#define O_CREAT SYS_O_CREAT
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC SYS_O_TRUNC
+#endif
+#ifndef O_RDWR
+#define O_RDWR SYS_O_RDWR
+#endif
+#else
+#include <cell/cell_fs.h>
+#ifndef O_RDONLY
+#define O_RDONLY CELL_FS_O_RDONLY
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY CELL_FS_O_WRONLY
+#endif
+#ifndef O_CREAT
+#define O_CREAT CELL_FS_O_CREAT
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC CELL_FS_O_TRUNC
+#endif
+#ifndef O_RDWR
+#define O_RDWR CELL_FS_O_RDWR
+#endif
+#ifndef sysFsStat
+#define sysFsStat cellFsStat
+#endif
+#ifndef sysFSDirent
+#define sysFSDirent CellFsDirent
+#endif
+#ifndef sysFsOpendir
+#define sysFsOpendir cellFsOpendir
+#endif
+#ifndef sysFsReaddir
+#define sysFsReaddir cellFsReaddir
+#endif
+#ifndef sysFSDirent
+#define sysFSDirent CellFsDirent
+#endif
+#ifndef sysFsClosedir
+#define sysFsClosedir cellFsClosedir
+#endif
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/defines/ps4_defines.h b/deps/libretro-common/include/defines/ps4_defines.h
new file mode 100644 (file)
index 0000000..5951b83
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _PS4_DEFINES_H
+#define _PS4_DEFINES_H
+
+#define PS4_MAX_ORBISPADS 16
+#define PS4_MAX_PAD_PORT_TYPES 3
+
+#define        ORBISPAD_L3                     0x00000002
+#define        ORBISPAD_R3                     0x00000004
+#define        ORBISPAD_OPTIONS            0x00000008
+#define        ORBISPAD_UP                     0x00000010
+#define        ORBISPAD_RIGHT              0x00000020
+#define        ORBISPAD_DOWN                 0x00000040
+#define        ORBISPAD_LEFT                 0x00000080
+#define        ORBISPAD_L2                     0x00000100
+#define        ORBISPAD_R2                     0x00000200
+#define        ORBISPAD_L1                     0x00000400
+#define        ORBISPAD_R1                     0x00000800
+#define        ORBISPAD_TRIANGLE           0x00001000
+#define        ORBISPAD_CIRCLE             0x00002000
+#define        ORBISPAD_CROSS              0x00004000
+#define        ORBISPAD_SQUARE             0x00008000
+#define        ORBISPAD_TOUCH_PAD        0x00100000
+#define        ORBISPAD_INTERCEPTED    0x80000000
+
+#define SceUID uint32_t
+#define SceKernelStat OrbisKernelStat
+#define SCE_KERNEL_PRIO_FIFO_DEFAULT 700
+#define SCE_AUDIO_OUT_PORT_TYPE_MAIN   0
+#define SCE_AUDIO_OUT_MODE_STEREO      1
+#define SCE_MOUSE_BUTTON_PRIMARY 0x00000001
+#define SCE_MOUSE_BUTTON_SECONDARY 0x00000002
+#define SCE_MOUSE_BUTTON_OPTIONAL 0x00000004
+#define SCE_MOUSE_BUTTON_INTERCEPTED 0x80000000
+#define SCE_MOUSE_OPEN_PARAM_MERGED    0x01
+#define SCE_MOUSE_PORT_TYPE_STANDARD 0
+#define SCE_DBG_KEYBOARD_PORT_TYPE_STANDARD    0
+#define SCE_USER_SERVICE_MAX_LOGIN_USERS 16
+#define SCE_USER_SERVICE_USER_ID_INVALID 0xFFFFFFFF
+#define SCE_ORBISPAD_ERROR_ALREADY_OPENED 0x80920004
+#define SCE_PAD_PORT_TYPE_STANDARD 0
+#define SCE_PAD_PORT_TYPE_SPECIAL      2
+#define SCE_PAD_PORT_TYPE_REMOTE_CONTROL 16
+#define SCE_KERNEL_PROT_CPU_RW 0x02
+#define SCE_KERNEL_MAP_FIXED 0x10
+
+#endif
diff --git a/deps/libretro-common/include/defines/psp_defines.h b/deps/libretro-common/include/defines/psp_defines.h
new file mode 100644 (file)
index 0000000..5f7b7cf
--- /dev/null
@@ -0,0 +1,145 @@
+/* Copyright (C) 2010-2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (psp_defines.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _PSP_DEFINES_H
+#define _PSP_DEFINES_H
+
+/*============================================================
+       ERROR PROTOTYPES
+============================================================ */
+
+#ifndef SCE_OK
+#define SCE_OK 0
+#endif
+
+/*============================================================
+       DISPLAY PROTOTYPES
+============================================================ */
+
+#if defined(SN_TARGET_PSP2) || defined(VITA)
+
+#ifdef VITA
+int sceClibPrintf ( const char * format, ... );
+#define printf sceClibPrintf
+#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
+#else
+#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
+#endif
+
+#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, sync)
+
+#define PSP_FB_WIDTH        960
+#define PSP_FB_HEIGHT       544
+#define PSP_PITCH_PIXELS 1024
+
+ // Memory left to the system for threads and other internal stuffs
+#ifdef SCE_LIBC_SIZE
+#define RAM_THRESHOLD 0x2000000 + SCE_LIBC_SIZE
+#else
+#define RAM_THRESHOLD 0x2000000
+#endif
+
+#elif defined(PSP)
+#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync)
+
+#define SCE_DISPLAY_UPDATETIMING_NEXTVSYNC 1
+
+#define PSP_FB_WIDTH        512
+#define PSP_FB_HEIGHT       512
+#define PSP_PITCH_PIXELS 512
+
+#endif
+
+/*============================================================
+       INPUT PROTOTYPES
+============================================================ */
+
+#if defined(SN_TARGET_PSP2) || defined(VITA)
+
+#define STATE_BUTTON(state) ((state).buttons)
+#define STATE_ANALOGLX(state) ((state).lx)
+#define STATE_ANALOGLY(state) ((state).ly)
+#define STATE_ANALOGRX(state) ((state).rx)
+#define STATE_ANALOGRY(state) ((state).ry)
+
+#if defined(VITA)
+#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_ANALOG)
+
+#define PSP_CTRL_LEFT SCE_CTRL_LEFT
+#define PSP_CTRL_DOWN SCE_CTRL_DOWN
+#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT
+#define PSP_CTRL_UP SCE_CTRL_UP
+#define PSP_CTRL_START SCE_CTRL_START
+#define PSP_CTRL_SELECT SCE_CTRL_SELECT
+#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE
+#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE
+#define PSP_CTRL_CROSS SCE_CTRL_CROSS
+#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE
+#define PSP_CTRL_L SCE_CTRL_L1
+#define PSP_CTRL_R SCE_CTRL_R1
+#define PSP_CTRL_L2 SCE_CTRL_LTRIGGER
+#define PSP_CTRL_R2 SCE_CTRL_RTRIGGER
+#define PSP_CTRL_L3 SCE_CTRL_L3
+#define PSP_CTRL_R3 SCE_CTRL_R3
+#else
+#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_DIGITALANALOG)
+
+#define PSP_CTRL_LEFT SCE_CTRL_LEFT
+#define PSP_CTRL_DOWN SCE_CTRL_DOWN
+#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT
+#define PSP_CTRL_UP SCE_CTRL_UP
+#define PSP_CTRL_START SCE_CTRL_START
+#define PSP_CTRL_SELECT SCE_CTRL_SELECT
+#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE
+#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE
+#define PSP_CTRL_CROSS SCE_CTRL_CROSS
+#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE
+#define PSP_CTRL_L SCE_CTRL_L
+#define PSP_CTRL_R SCE_CTRL_R
+#endif
+
+#if defined(VITA)
+#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingModeExt(mode)
+#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositiveExt2(port, pad_data, bufs)
+#else
+#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)
+#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(port, pad_data, bufs)
+#endif
+
+#elif defined(PSP)
+
+#define PSP_CTRL_L PSP_CTRL_LTRIGGER
+#define PSP_CTRL_R PSP_CTRL_RTRIGGER
+
+#define STATE_BUTTON(state) ((state).Buttons)
+#define STATE_ANALOGLX(state) ((state).Lx)
+#define STATE_ANALOGLY(state) ((state).Ly)
+#define STATE_ANALOGRX(state) ((state).Rx)
+#define STATE_ANALOGRY(state) ((state).Ry)
+
+#define DEFAULT_SAMPLING_MODE (PSP_CTRL_MODE_ANALOG)
+
+#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)
+#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(pad_data, bufs)
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/dynamic/dylib.h b/deps/libretro-common/include/dynamic/dylib.h
new file mode 100644 (file)
index 0000000..6a52b95
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (dylib.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __DYLIB_H
+#define __DYLIB_H
+
+#include <boolean.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <retro_common_api.h>
+
+#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)
+#define NEED_DYNAMIC
+#else
+#undef NEED_DYNAMIC
+#endif
+
+RETRO_BEGIN_DECLS
+
+typedef void *dylib_t;
+typedef void (*function_t)(void);
+
+#ifdef NEED_DYNAMIC
+/**
+ * dylib_load:
+ * @path                         : Path to libretro core library.
+ *
+ * Platform independent dylib loading.
+ *
+ * @return Library handle on success, otherwise NULL.
+ **/
+dylib_t dylib_load(const char *path);
+
+/**
+ * dylib_close:
+ * @lib                          : Library handle.
+ *
+ * Frees library handle.
+ **/
+void dylib_close(dylib_t lib);
+
+char *dylib_error(void);
+
+function_t dylib_proc(dylib_t lib, const char *proc);
+#endif
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/encodings/base64.h b/deps/libretro-common/include/encodings/base64.h
new file mode 100644 (file)
index 0000000..1380851
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _LIBRETRO_ENCODINGS_BASE64_H
+#define _LIBRETRO_ENCODINGS_BASE64_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+char* base64(const void* binaryData, int len, int *flen);
+unsigned char* unbase64(const char* ascii, int len, int *flen);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/encodings/crc32.h b/deps/libretro-common/include/encodings/crc32.h
new file mode 100644 (file)
index 0000000..5f26cc7
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (crc32.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_ENCODINGS_CRC32_H
+#define _LIBRETRO_ENCODINGS_CRC32_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+uint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/encodings/utf.h b/deps/libretro-common/include/encodings/utf.h
new file mode 100644 (file)
index 0000000..ccd08fa
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (utf.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_ENCODINGS_UTF_H
+#define _LIBRETRO_ENCODINGS_UTF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <boolean.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+enum CodePage
+{
+   CODEPAGE_LOCAL = 0, /* CP_ACP */
+   CODEPAGE_UTF8  = 65001 /* CP_UTF8 */
+};
+
+/**
+ * utf8_conv_utf32:
+ *
+ * Simple implementation. Assumes the sequence is
+ * properly synchronized and terminated.
+ **/
+size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
+      const char *in, size_t in_size);
+
+/**
+ * utf16_conv_utf8:
+ *
+ * Leaf function.
+ **/
+bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
+      const uint16_t *in, size_t in_size);
+
+/**
+ * utf8len:
+ *
+ * Leaf function.
+ **/
+size_t utf8len(const char *string);
+
+/**
+ * utf8cpy:
+ *
+ * Acts mostly like strlcpy.
+ *
+ * Copies the given number of UTF-8 characters,
+ * but at most @d_len bytes.
+ *
+ * Always NULL terminates. Does not copy half a character.
+ * @s is assumed valid UTF-8.
+ * Use only if @chars is considerably less than @d_len. 
+ *
+ * Hidden non-leaf function cost:
+ * - Calls memcpy
+ *
+ * @return Number of bytes. 
+ **/
+size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
+
+/**
+ * utf8skip:
+ *
+ * Leaf function
+ **/
+const char *utf8skip(const char *str, size_t chars);
+
+/** 
+ * utf8_walk:
+ *
+ * Does not validate the input.
+ *
+ * Leaf function.
+ *
+ * @return Returns garbage if it's not UTF-8.
+ **/
+uint32_t utf8_walk(const char **string);
+
+/**
+ * utf16_to_char_string:
+ **/
+bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
+
+/**
+ * utf8_to_local_string_alloc:
+ *
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+char *utf8_to_local_string_alloc(const char *str);
+
+/**
+ * local_to_utf8_string_alloc:
+ *
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+char *local_to_utf8_string_alloc(const char *str);
+
+/**
+ * utf8_to_utf16_string_alloc:
+ * 
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+wchar_t *utf8_to_utf16_string_alloc(const char *str);
+
+/**
+ * utf16_to_utf8_string_alloc:
+ *
+ * @return Returned pointer MUST be freed by the caller if non-NULL.
+ **/
+char *utf16_to_utf8_string_alloc(const wchar_t *str);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/encodings/win32.h b/deps/libretro-common/include/encodings/win32.h
new file mode 100644 (file)
index 0000000..8104af0
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (utf.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_ENCODINGS_WIN32_H
+#define _LIBRETRO_ENCODINGS_WIN32_H
+
+#ifndef _XBOX
+#ifdef _WIN32
+/*#define UNICODE
+#include <tchar.h>
+#include <wchar.h>*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <encodings/utf.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
+
+#ifdef UNICODE
+#define CHAR_TO_WCHAR_ALLOC(s, ws) \
+   size_t ws##_size = (NULL != s && s[0] ? strlen(s) : 0) + 1; \
+   wchar_t *ws = (wchar_t*)calloc(ws##_size, 2); \
+   if (NULL != s && s[0]) \
+      MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws##_size / sizeof(wchar_t));
+
+#define WCHAR_TO_CHAR_ALLOC(ws, s) \
+   size_t s##_size = ((NULL != ws && ws[0] ? wcslen((const wchar_t*)ws) : 0) / 2) + 1; \
+   char *s = (char*)calloc(s##_size, 1); \
+   if (NULL != ws && ws[0]) \
+      utf16_to_char_string((const uint16_t*)ws, s, s##_size);
+
+#else
+#define CHAR_TO_WCHAR_ALLOC(s, ws) char *ws = (NULL != s && s[0] ? strdup(s) : NULL);
+#define WCHAR_TO_CHAR_ALLOC(ws, s) char *s = (NULL != ws && ws[0] ? strdup(ws) : NULL);
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/fastcpy.h b/deps/libretro-common/include/fastcpy.h
new file mode 100644 (file)
index 0000000..7ecd460
--- /dev/null
@@ -0,0 +1,93 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fastcpy.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* in the future ASM and new c++ features can be added to speed up copying */
+#include <stdint.h>
+#include <string.h>
+#include <retro_inline.h>
+
+static INLINE void* memcpy16(void* dst,void* src,size_t size)
+{
+   return memcpy(dst,src,size * 2);
+}
+
+static INLINE void* memcpy32(void* dst,void* src,size_t size)
+{
+   return memcpy(dst,src,size * 4);
+}
+
+static INLINE void* memcpy64(void* dst,void* src,size_t size)
+{
+   return memcpy(dst,src,size * 8);
+}
+
+#ifdef USECPPSTDFILL
+#include <algorithm>
+
+static INLINE void* memset16(void* dst,uint16_t val,size_t size)
+{
+   uint16_t *typedptr = (uint16_t*)dst;
+   std::fill(typedptr, typedptr + size, val);
+   return dst;
+}
+
+static INLINE void* memset32(void* dst,uint32_t val,size_t size)
+{
+   uint32_t *typedptr = (uint32_t*)dst;
+   std::fill(typedptr, typedptr + size, val);
+   return dst;
+}
+
+static INLINE void* memset64(void* dst,uint64_t val,size_t size)
+{
+   uint64_t *typedptr = (uint64_t*)dst;
+   std::fill(typedptr, typedptr + size, val);
+   return dst;
+}
+#else
+static INLINE void *memset16(void* dst,uint16_t val,size_t size)
+{
+   size_t i;
+   uint16_t *typedptr = (uint16_t*)dst;
+   for (i = 0;i < size;i++)
+      typedptr[i] = val;
+   return dst;
+}
+
+static INLINE void *memset32(void* dst,uint32_t val,size_t size)
+{
+   size_t i;
+   uint32_t *typedptr = (uint32_t*)dst;
+   for (i = 0; i < size; i++)
+      typedptr[i] = val;
+   return dst;
+}
+
+static INLINE void *memset64(void* dst,uint64_t val,size_t size)
+{
+   size_t i;
+   uint64_t *typedptr = (uint64_t*)dst;
+   for (i = 0; i < size;i++)
+      typedptr[i] = val;
+   return dst;
+}
+#endif
diff --git a/deps/libretro-common/include/features/features_cpu.h b/deps/libretro-common/include/features/features_cpu.h
new file mode 100644 (file)
index 0000000..130d748
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (features_cpu.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_CPU_INFO_H
+#define _LIBRETRO_SDK_CPU_INFO_H
+
+#include <retro_common_api.h>
+
+#include <stdint.h>
+
+#include <libretro.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * cpu_features_get_perf_counter:
+ *
+ * Gets performance counter.
+ *
+ * @return Performance counter.
+ **/
+retro_perf_tick_t cpu_features_get_perf_counter(void);
+
+/**
+ * cpu_features_get_time_usec:
+ *
+ * Gets time in microseconds, from an undefined epoch.
+ * The epoch may change between computers or across reboots.
+ *
+ * @return Time in microseconds
+ **/
+retro_time_t cpu_features_get_time_usec(void);
+
+/**
+ * cpu_features_get:
+ *
+ * Gets CPU features.
+ *
+ * @return Bitmask of all CPU features available.
+ **/
+uint64_t cpu_features_get(void);
+
+/**
+ * cpu_features_get_core_amount:
+ *
+ * Gets the amount of available CPU cores.
+ *
+ * @return Amount of CPU cores available.
+ **/
+unsigned cpu_features_get_core_amount(void);
+
+void cpu_features_get_model_name(char *name, int len);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/file/archive_file.h b/deps/libretro-common/include/file/archive_file.h
new file mode 100644 (file)
index 0000000..7a0a9f7
--- /dev/null
@@ -0,0 +1,210 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (archive_file.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_SDK_ARCHIVE_FILE_H__
+#define LIBRETRO_SDK_ARCHIVE_FILE_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <boolean.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <retro_miscellaneous.h>
+
+#include <retro_common_api.h>
+
+#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
+#include "../../../config.h" /* for HAVE_MMAP */
+#endif
+
+RETRO_BEGIN_DECLS
+
+enum file_archive_transfer_type
+{
+   ARCHIVE_TRANSFER_NONE = 0,
+   ARCHIVE_TRANSFER_INIT,
+   ARCHIVE_TRANSFER_ITERATE,
+   ARCHIVE_TRANSFER_DEINIT,
+   ARCHIVE_TRANSFER_DEINIT_ERROR
+};
+
+typedef struct file_archive_handle
+{
+   uint8_t  *data;
+   uint32_t real_checksum;
+} file_archive_file_handle_t;
+
+typedef struct file_archive_transfer
+{
+   int64_t archive_size;
+   void *context;
+   struct RFILE *archive_file;
+   const struct file_archive_file_backend *backend;
+#ifdef HAVE_MMAP
+   uint8_t *archive_mmap_data;
+   int archive_mmap_fd;
+#endif
+   unsigned step_total;
+   unsigned step_current;
+   enum file_archive_transfer_type type;
+} file_archive_transfer_t;
+
+typedef struct
+{
+   file_archive_transfer_t archive;             /* int64_t alignment */
+   char *source_file;
+   char *subdir;
+   char *target_dir;
+   char *target_file;
+   char *valid_ext;
+   char *callback_error;
+   struct archive_extract_userdata *userdata;
+} decompress_state_t;
+
+struct archive_extract_userdata
+{
+   /* These are set or read by the archive processing */
+   char *first_extracted_file_path;
+   const char *extraction_directory;
+   struct string_list *ext;
+   struct string_list *list;
+   file_archive_transfer_t *transfer;
+   /* Not used by the processing, free to use outside or in iterate callback */
+   decompress_state_t *dec;
+   void* cb_data;
+   uint32_t crc;
+   char archive_path[PATH_MAX_LENGTH];
+   char current_file_path[PATH_MAX_LENGTH];
+   bool found_file;
+   bool list_only;
+};
+
+/* Returns true when parsing should continue. False to stop. */
+typedef int (*file_archive_file_cb)(const char *name, const char *valid_exts,
+      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
+      uint32_t crc32, struct archive_extract_userdata *userdata);
+
+struct file_archive_file_backend
+{
+   int (*archive_parse_file_init)(
+      file_archive_transfer_t *state,
+      const char *file);
+   int (*archive_parse_file_iterate_step)(
+      void *context,
+      const char *valid_exts,
+      struct archive_extract_userdata *userdata,
+      file_archive_file_cb file_cb);
+   void (*archive_parse_file_free)(
+      void *context);
+
+   bool     (*stream_decompress_data_to_file_init)(
+      void *context, file_archive_file_handle_t *handle,
+      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size);
+   int      (*stream_decompress_data_to_file_iterate)(
+      void *context,
+      file_archive_file_handle_t *handle);
+
+   uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t);
+   int64_t (*compressed_file_read)(const char *path, const char *needle, void **buf,
+         const char *optional_outfile);
+   const char *ident;
+};
+
+int file_archive_parse_file_iterate(
+      file_archive_transfer_t *state,
+      bool *returnerr,
+      const char *file,
+      const char *valid_exts,
+      file_archive_file_cb file_cb,
+      struct archive_extract_userdata *userdata);
+
+void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state);
+
+int file_archive_parse_file_progress(file_archive_transfer_t *state);
+
+/**
+ * file_archive_extract_file:
+ * @archive_path                : filename path to ZIP archive.
+ * @valid_exts                  : valid extensions for a file.
+ * @extraction_directory        : the directory to extract the temporary
+ *                                file to.
+ *
+ * Extract file from archive. If no file inside the archive is
+ * specified, the first file found will be used.
+ *
+ * Returns : true (1) on success, otherwise false (0).
+ **/
+bool file_archive_extract_file(const char *archive_path,
+      const char *valid_exts, const char *extraction_dir,
+      char *out_path, size_t len);
+
+/* Warning: 'list' must zero initialised before
+ * calling this function, otherwise memory leaks/
+ * undefined behaviour will occur */
+bool file_archive_get_file_list_noalloc(struct string_list *list,
+      const char *path,
+      const char *valid_exts);
+
+/**
+ * file_archive_get_file_list:
+ * @path                        : filename path of archive
+ * @valid_exts                  : Valid extensions of archive to be parsed.
+ *                                If NULL, allow all.
+ *
+ * Returns: string listing of files from archive on success, otherwise NULL.
+ **/
+struct string_list* file_archive_get_file_list(const char *path, const char *valid_exts);
+
+bool file_archive_perform_mode(const char *name, const char *valid_exts,
+      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
+      uint32_t crc32, struct archive_extract_userdata *userdata);
+
+int file_archive_compressed_read(
+      const char* path, void **buf,
+      const char* optional_filename, int64_t *length);
+
+const struct file_archive_file_backend* file_archive_get_zlib_file_backend(void);
+const struct file_archive_file_backend* file_archive_get_7z_file_backend(void);
+
+const struct file_archive_file_backend* file_archive_get_file_backend(const char *path);
+
+/**
+ * file_archive_get_file_crc32:
+ * @path                         : filename path of archive
+ *
+ * Returns: CRC32 of the specified file in the archive, otherwise 0.
+ * If no path within the archive is specified, the first
+ * file found inside is used.
+ **/
+uint32_t file_archive_get_file_crc32(const char *path);
+
+extern const struct file_archive_file_backend zlib_backend;
+extern const struct file_archive_file_backend sevenzip_backend;
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/file/config_file.h b/deps/libretro-common/include/file/config_file.h
new file mode 100644 (file)
index 0000000..4d2d232
--- /dev/null
@@ -0,0 +1,330 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (config_file.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_CONFIG_FILE_H
+#define __LIBRETRO_SDK_CONFIG_FILE_H
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include <boolean.h>
+
+#define CONFIG_GET_BOOL_BASE(conf, base, var, key) do { \
+   bool tmp = false; \
+   if (config_get_bool(conf, key, &tmp)) \
+      base->var = tmp; \
+} while(0)
+
+#define CONFIG_GET_INT_BASE(conf, base, var, key) do { \
+   int tmp = 0; \
+   if (config_get_int(conf, key, &tmp)) \
+      base->var = tmp; \
+} while(0)
+
+#define CONFIG_GET_FLOAT_BASE(conf, base, var, key) do { \
+   float tmp = 0.0f; \
+   if (config_get_float(conf, key, &tmp)) \
+      base->var = tmp; \
+} while(0)
+
+struct config_file
+{
+   char *path;
+   struct config_entry_list **entries_map;
+   struct config_entry_list *entries;
+   struct config_entry_list *tail;
+   struct config_entry_list *last;
+   struct config_include_list *includes;
+   struct path_linked_list *references;
+   unsigned include_depth;
+   bool guaranteed_no_duplicates;
+   bool modified;
+};
+
+typedef struct config_file config_file_t;
+
+struct config_file_cb
+{
+   void (*config_file_new_entry_cb)(char*, char*);
+};
+
+typedef struct config_file_cb config_file_cb_t ;
+
+/* Config file format
+ * - # are treated as comments. Rest of the line is ignored.
+ * - Format is: key = value. There can be as many spaces as you like in-between.
+ * - Value can be wrapped inside "" for multiword strings. (foo = "hai u")
+ * - #include includes a config file in-place.
+ *
+ * Path is relative to where config file was loaded unless an absolute path is chosen.
+ * Key/value pairs from an #include are read-only, and cannot be modified.
+ */
+
+/**
+ * config_file_new:
+ *
+ * Loads a config file.
+ * If @path is NULL, will create an empty config file.
+ *
+ * @return Returns NULL if file doesn't exist.
+ **/
+config_file_t *config_file_new(const char *path);
+
+config_file_t *config_file_new_alloc(void);
+
+/**
+ * config_file_initialize:
+ *
+ * Leaf function.
+ **/
+void config_file_initialize(struct config_file *conf);
+
+/**
+ * config_file_new_with_callback:
+ *
+ * Loads a config file.
+ * If @path is NULL, will create an empty config file.
+ * Includes cb callbacks  to run custom code during config file processing.
+ *
+ * @return Returns NULL if file doesn't exist.
+ **/
+config_file_t *config_file_new_with_callback(
+      const char *path, config_file_cb_t *cb);
+
+/**
+ * config_file_new_from_string:
+ *
+ * Load a config file from a string.
+ *
+ * NOTE: This will modify @from_string.
+ * Pass a copy of source string if original
+ * contents must be preserved
+ **/
+config_file_t *config_file_new_from_string(char *from_string,
+      const char *path);
+
+config_file_t *config_file_new_from_path_to_string(const char *path);
+
+/**
+ * config_file_free:
+ *
+ * Frees config file.
+ **/
+void config_file_free(config_file_t *conf);
+
+void config_file_add_reference(config_file_t *conf, char *path);
+
+bool config_file_deinitialize(config_file_t *conf);
+
+/**
+ * config_append_file:
+ *
+ * Loads a new config, and appends its data to @conf.
+ * The key-value pairs of the new config file takes priority over the old.
+ **/
+bool config_append_file(config_file_t *conf, const char *path);
+
+/* All extract functions return true when value is valid and exists.
+ * Returns false otherwise. */
+
+struct config_entry_list
+{
+   char *key;
+   char *value;
+   struct config_entry_list *next;
+   /* If we got this from an #include,
+    * do not allow overwrite. */
+   bool readonly;
+};
+
+struct config_file_entry
+{
+   const char *key;
+   const char *value;
+   /* Used intentionally. Opaque here. */
+   const struct config_entry_list *next;
+};
+
+struct config_entry_list *config_get_entry(
+      const config_file_t *conf, const char *key);
+
+/**
+ * config_get_entry_list_head:
+ *
+ * Leaf function.
+ **/
+bool config_get_entry_list_head(config_file_t *conf,
+      struct config_file_entry *entry);
+
+/**
+ * config_get_entry_list_next:
+ *
+ * Leaf function.
+ **/
+bool config_get_entry_list_next(struct config_file_entry *entry);
+
+/**
+ * config_get_double:
+ *
+ * Extracts a double from config file.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls config_get_entry()
+ * - Calls strtod
+ *
+ * @return True if double found, otherwise false.
+ **/
+bool config_get_double(config_file_t *conf, const char *entry, double *in);
+
+/**
+ * config_get_float:
+ *
+ * Extracts a float from config file.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls config_get_entry()
+ * - Calls strtod
+ *
+ * @return true if found, otherwise false.
+ **/
+bool config_get_float(config_file_t *conf, const char *entry, float *in);
+
+/* Extracts an int from config file. */
+bool config_get_int(config_file_t *conf, const char *entry, int *in);
+
+/* Extracts an uint from config file. */
+bool config_get_uint(config_file_t *conf, const char *entry, unsigned *in);
+
+/* Extracts an size_t from config file. */
+bool config_get_size_t(config_file_t *conf, const char *key, size_t *in);
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
+/* Extracts an uint64 from config file. */
+bool config_get_uint64(config_file_t *conf, const char *entry, uint64_t *in);
+#endif
+
+/* Extracts an unsigned int from config file treating input as hex. */
+bool config_get_hex(config_file_t *conf, const char *entry, unsigned *in);
+
+/**
+ * config_get_char:
+ *
+ * Extracts a single char from config file.
+ * If value consists of several chars, this is an error.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls config_get_entry()
+ *
+ * @return true if found, otherwise false.
+ **/
+bool config_get_char(config_file_t *conf, const char *entry, char *in);
+
+/**
+ * config_get_string:
+ *
+ * Extracts an allocated string in *in. This must be free()-d if
+ * this function succeeds.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls config_get_entry()
+ * - Calls strdup
+ *
+ * @return true if found, otherwise false.
+ **/
+bool config_get_string(config_file_t *conf, const char *entry, char **in);
+
+/* Extracts a string to a preallocated buffer. Avoid memory allocation. */
+bool config_get_array(config_file_t *conf, const char *entry, char *s, size_t len);
+
+/**
+  * config_get_config_path:
+  *
+  * Extracts a string to a preallocated buffer.
+  * Avoid memory allocation.
+  *
+  * Hidden non-leaf function cost:
+  * - Calls strlcpy
+  **/
+bool config_get_config_path(config_file_t *conf, char *s, size_t len);
+
+/* Extracts a string to a preallocated buffer. Avoid memory allocation.
+ * Recognized magic like ~/. Similar to config_get_array() otherwise. */
+bool config_get_path(config_file_t *conf, const char *entry, char *s, size_t len);
+
+/**
+ * config_get_bool:
+ * 
+ * Extracts a boolean from config.
+ * Valid boolean true are "true" and "1". Valid false are "false" and "0".
+ * Other values will be treated as an error.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls string_is_equal() x times
+ *
+ * @return true if preconditions are true, otherwise false.
+ **/
+bool config_get_bool(config_file_t *conf, const char *entry, bool *in);
+
+/* Setters. Similar to the getters.
+ * Will not write to entry if the entry was obtained from an #include. */
+void config_set_double(config_file_t *conf, const char *entry, double value);
+void config_set_float(config_file_t *conf, const char *entry, float value);
+void config_set_int(config_file_t *conf, const char *entry, int val);
+void config_set_hex(config_file_t *conf, const char *entry, unsigned val);
+void config_set_uint64(config_file_t *conf, const char *entry, uint64_t val);
+void config_set_char(config_file_t *conf, const char *entry, char val);
+void config_set_string(config_file_t *conf, const char *entry, const char *val);
+void config_unset(config_file_t *conf, const char *key);
+void config_set_path(config_file_t *conf, const char *entry, const char *val);
+
+/**
+ * config_set_bool:
+
+ * TODO/FIXME - could be turned into a trivial macro or removed
+ **/
+void config_set_bool(config_file_t *conf, const char *entry, bool val);
+
+void config_set_uint(config_file_t *conf, const char *key, unsigned int val);
+
+/**
+ * config_file_write:
+ *
+ * Write the current config to a file.
+ **/
+bool config_file_write(config_file_t *conf, const char *path, bool val);
+
+/**
+ * config_file_dump:
+ *
+ * Dump the current config to an already opened file.
+ * Does not close the file.
+ **/
+void config_file_dump(config_file_t *conf, FILE *file, bool val);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/file/config_file_userdata.h b/deps/libretro-common/include/file/config_file_userdata.h
new file mode 100644 (file)
index 0000000..0490da2
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (config_file_userdata.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H
+#define _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H
+
+#include <string.h>
+
+#include <file/config_file.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+struct config_file_userdata
+{
+   config_file_t *conf;
+   const char *prefix[2];
+};
+
+int config_userdata_get_float(void *userdata, const char *key_str,
+      float *value, float default_value);
+
+int config_userdata_get_int(void *userdata, const char *key_str,
+      int *value, int default_value);
+
+int config_userdata_get_hex(void *userdata, const char *key_str,
+      unsigned *value, unsigned default_value);
+
+int config_userdata_get_float_array(void *userdata, const char *key_str,
+      float **values, unsigned *out_num_values,
+      const float *default_values, unsigned num_default_values);
+
+int config_userdata_get_int_array(void *userdata, const char *key_str,
+      int **values, unsigned *out_num_values,
+      const int *default_values, unsigned num_default_values);
+
+int config_userdata_get_string(void *userdata, const char *key_str,
+      char **output, const char *default_output);
+
+void config_userdata_free(void *ptr);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/file/file_path.h b/deps/libretro-common/include/file/file_path.h
new file mode 100644 (file)
index 0000000..3aa81f5
--- /dev/null
@@ -0,0 +1,684 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_path.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FILE_PATH_H
+#define __LIBRETRO_SDK_FILE_PATH_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <libretro.h>
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+#define PATH_REQUIRED_VFS_VERSION 3
+
+void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);
+
+/* Order in this enum is equivalent to negative sort order in filelist
+ *  (i.e. DIRECTORY is on top of PLAIN_FILE) */
+enum
+{
+   RARCH_FILETYPE_UNSET,
+   RARCH_PLAIN_FILE,
+   RARCH_COMPRESSED_FILE_IN_ARCHIVE,
+   RARCH_COMPRESSED_ARCHIVE,
+   RARCH_DIRECTORY,
+   RARCH_FILE_UNSUPPORTED
+};
+
+struct path_linked_list
+{
+   char *path;
+   struct path_linked_list *next;
+};
+
+/**
+ * Create a new linked list with one item in it
+ * The path on this item will be set to NULL
+**/
+struct path_linked_list* path_linked_list_new(void);
+
+/* Free the entire linked list */
+void path_linked_list_free(struct path_linked_list *in_path_linked_list);
+
+/**
+ * Add a node to the linked list with this path
+ * If the first node's path if it's not yet set, 
+ * set this instead
+**/
+void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);
+
+/**
+ * path_is_compressed_file:
+ * @path               : path
+ *
+ * Checks if path is a compressed file.
+ *
+ * Returns: true (1) if path is a compressed file, otherwise false (0).
+ **/
+bool path_is_compressed_file(const char *path);
+
+/**
+ * path_contains_compressed_file:
+ * @path               : path
+ *
+ * Checks if path contains a compressed file.
+ *
+ * Currently we only check for hash symbol (#) inside the pathname.
+ * If path is ever expanded to a general URI, we should check for that here.
+ *
+ * Example:  Somewhere in the path there might be a compressed file
+ * E.g.: /path/to/file.7z#mygame.img
+ *
+ * Returns: true (1) if path contains compressed file, otherwise false (0).
+ **/
+#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)
+
+/**
+ * path_get_archive_delim:
+ * @path               : path
+ *
+ * Find delimiter of an archive file. Only the first '#'
+ * after a compression extension is considered.
+ *
+ * @return pointer to the delimiter in the path if it contains
+ * a path inside a compressed file, otherwise NULL.
+ **/
+const char *path_get_archive_delim(const char *path);
+
+/**
+ * path_get_extension:
+ * @path               : path
+ *
+ * Gets extension of file. Only '.'s
+ * after the last slash are considered.
+ *
+ * Hidden non-leaf function cost:
+ * - calls string_is_empty()
+ * - calls strrchr
+ *
+ * @return extension part from the path.
+ **/
+const char *path_get_extension(const char *path);
+
+/**
+ * path_get_extension_mutable:
+ * @path               : path
+ *
+ * Specialized version of path_get_extension(). Return
+ * value is mutable.
+ *
+ * Gets extension of file. Only '.'s
+ * after the last slash are considered.
+ *
+ * @return extension part from the path.
+ **/
+char *path_get_extension_mutable(const char *path);
+
+/**
+ * path_remove_extension:
+ * @path               : path
+ *
+ * Mutates path by removing its extension. Removes all
+ * text after and including the last '.'.
+ * Only '.'s after the last slash are considered.
+ *
+ * Hidden non-leaf function cost:
+ * - calls strrchr
+ *
+ * @return
+ * 1) If path has an extension, returns path with the
+ *    extension removed.
+ * 2) If there is no extension, returns NULL.
+ * 3) If path is empty or NULL, returns NULL
+ */
+char *path_remove_extension(char *path);
+
+/**
+ * path_basename:
+ * @path               : path
+ *
+ * Get basename from @path.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls path_get_archive_delim()
+ *   - can call find_last_slash() once if it returns NULL
+ *
+ * @return basename from path.
+ **/
+const char *path_basename(const char *path);
+
+/**
+ * path_basename_nocompression:
+ * @path               : path
+ *
+ * Specialized version of path_basename().
+ * Get basename from @path.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls find_last_slash()
+ *
+ * @return basename from path.
+ **/
+const char *path_basename_nocompression(const char *path);
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir(char *path);
+
+/**
+ * path_parent_dir:
+ * @path               : path
+ * @len                : length of @path
+ *
+ * Extracts parent directory by mutating path.
+ * Assumes that path is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory, returns empty string
+ **/
+void path_parent_dir(char *path, size_t len);
+
+/**
+ * path_resolve_realpath:
+ * @buf                : input and output buffer for path
+ * @size               : size of buffer
+ * @resolve_symlinks   : whether to resolve symlinks or not
+ *
+ * Resolves use of ".", "..", multiple slashes etc in absolute paths.
+ *
+ * Relative paths are rebased on the current working dir.
+ *
+ * @return @buf if successful, NULL otherwise.
+ * Note: Not implemented on consoles
+ * Note: Symlinks are only resolved on Unix-likes
+ * Note: The current working dir might not be what you expect,
+ *       e.g. on Android it is "/"
+ *       Use of fill_pathname_resolve_relative() should be prefered
+ **/
+char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
+
+/**
+ * path_relative_to:
+ * @out                : buffer to write the relative path to
+ * @path               : path to be expressed relatively
+ * @base               : relative to this
+ * @size               : size of output buffer
+ *
+ * Turns @path into a path relative to @base and writes it to @out.
+ *
+ * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
+ * Both @path and @base are assumed to be absolute paths without "." or "..".
+ *
+ * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
+ *
+ * @return Length of the string copied into @out
+ **/
+size_t path_relative_to(char *out, const char *path, const char *base,
+      size_t size);
+
+/**
+ * path_is_absolute:
+ * @path               : path
+ *
+ * Checks if @path is an absolute path or a relative path.
+ *
+ * @return true if path is absolute, false if path is relative.
+ **/
+bool path_is_absolute(const char *path);
+
+/**
+ * fill_pathname:
+ * @out_path           : output path
+ * @in_path            : input  path
+ * @replace            : what to replace
+ * @size               : buffer size of output path
+ *
+ * FIXME: Verify
+ *
+ * Replaces filename extension with 'replace' and outputs result to out_path.
+ * The extension here is considered to be the string from the last '.'
+ * to the end.
+ *
+ * Only '.'s after the last slash are considered as extensions.
+ * If no '.' is present, in_path and replace will simply be concatenated.
+ * 'size' is buffer size of 'out_path'.
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
+ * out_path = "/foo/bar/baz/boo.asm"
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =>
+ * out_path = "/foo/bar/baz/boo"
+ *
+ * Hidden non-leaf function cost:
+ * - calls strlcpy 2x
+ * - calls strrchr
+ * - calls strlcat
+ *
+ * @return Length of the string copied into @out
+ */
+size_t fill_pathname(char *out_path, const char *in_path,
+      const char *replace, size_t size);
+
+/**
+ * fill_dated_filename:
+ * @out_filename       : output filename
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by 'RetroArch', and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
+ *
+ * Hidden non-leaf function cost:
+ * - Calls rtime_localtime()
+ * - Calls strftime
+ * - Calls strlcat
+ *
+ **/
+size_t fill_dated_filename(char *out_filename,
+      const char *ext, size_t size);
+
+/**
+ * fill_str_dated_filename:
+ * @out_filename       : output filename
+ * @in_str             : input string
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by the string @in_str, and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
+ *
+ * Hidden non-leaf function cost:
+ * - Calls time
+ * - Calls rtime_localtime()
+ * - Calls strlcpy
+ * - Calls string_is_empty()
+ * - Calls strftime
+ * - Calls strlcat at least 2x
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_str_dated_filename(char *out_filename,
+      const char *in_str, const char *ext, size_t size);
+
+/**
+ * find_last_slash:
+ * @str                : path
+ * @size               : size of path
+ *
+ * Find last slash in path. Tries to find
+ * a backslash on Windows too which takes precedence
+ * over regular slash.
+
+ * Hidden non-leaf function cost: 
+ * - calls strrchr
+ *
+ * @return pointer to last slash/backslash found in @str.
+ **/
+char *find_last_slash(const char *str);
+
+/**
+ * fill_pathname_dir:
+ * @in_dir             : input directory path
+ * @in_basename        : input basename to be appended to @in_dir
+ * @replace            : replacement to be appended to @in_basename
+ * @size               : size of buffer
+ *
+ * Appends basename of 'in_basename', to 'in_dir', along with 'replace'.
+ * Basename of in_basename is the string after the last '/' or '\\',
+ * i.e the filename without directories.
+ *
+ * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
+ * 'size' is buffer size of 'in_dir'.
+ *
+ * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
+ * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
+ *
+ * Hidden non-leaf function cost:
+ * - Calls fill_pathname_slash()
+ * - Calls path_basename()
+ * - Calls strlcat 2x
+ **/
+size_t fill_pathname_dir(char *in_dir, const char *in_basename,
+      const char *replace, size_t size);
+
+/**
+ * fill_pathname_base:
+ * @out                : output path
+ * @in_path            : input path
+ * @size               : size of output path
+ *
+ * Copies basename of @in_path into @out_path.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls path_basename()
+ * - Calls strlcpy
+ *
+ * @return length of the string copied into @out
+ **/
+size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
+
+/**
+ * fill_pathname_basedir:
+ * @out_dir            : output directory
+ * @in_path            : input path
+ * @size               : size of output directory
+ *
+ * Copies base directory of @in_path into @out_path.
+ * If in_path is a path without any slashes (relative current directory),
+ * @out_path will get path "./".
+ *
+ * Hidden non-leaf function cost:
+ * - Calls strlcpy
+ * - Calls path_basedir()
+ **/
+void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
+
+/**
+ * fill_pathname_parent_dir_name:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies only the parent directory name of @in_dir into @out_dir.
+ * The two buffers must not overlap. Removes trailing '/'.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls strdup
+ * - Calls find_last_slash() x times
+ * - Can call strlcpy
+ *
+ * @return true on success, false if a slash was not found in the path.
+ **/
+bool fill_pathname_parent_dir_name(char *out_dir,
+      const char *in_dir, size_t size);
+
+/**
+ * fill_pathname_parent_dir:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies parent directory of @in_dir into @out_dir.
+ * Assumes @in_dir is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory, @out_dir will be an empty string.
+ *
+ * Hidden non-leaf function cost:
+ * - Can call strlcpy if (@out_dir != @in_dir)
+ * - Calls strlen if (@out_dir == @in_dir)
+ * - Calls path_parent_dir()
+ **/
+void fill_pathname_parent_dir(char *out_dir,
+      const char *in_dir, size_t size);
+
+/**
+ * fill_pathname_resolve_relative:
+ * @out_path           : output path
+ * @in_refpath         : input reference path
+ * @in_path            : input path
+ * @size               : size of @out_path
+ *
+ * Joins basedir of @in_refpath together with @in_path.
+ * If @in_path is an absolute path, out_path = in_path.
+ * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
+ * out_path = "/foo/bar/foobar.cg".
+ **/
+void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
+      const char *in_path, size_t size);
+
+/**
+ * fill_pathname_join:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together.
+ * Makes sure not to get two consecutive slashes
+ * between directory and path.
+ * 
+ * Hidden non-leaf function cost: 
+ * - calls strlcpy
+ * - calls fill_pathname_slash()
+ * - calls strlcat
+ *
+ * Deprecated. Use fill_pathname_join_special() instead
+ * if you can ensure @dir != @out_path
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_pathname_join(char *out_path, const char *dir,
+      const char *path, size_t size);
+
+/**
+ * fill_pathname_join_special:
+ * @out_path           : output path
+ * @dir                : directory. Cannot be identical to @out_path
+ * @path               : path
+ * @size               : size of output path
+ *
+ *
+ * Specialized version of fill_pathname_join.
+ * Unlike fill_pathname_join(),
+ * @dir and @out_path CANNOT be identical.
+ *
+ * Joins a directory (@dir) and path (@path) together.
+ * Makes sure not to get two consecutive slashes
+ * between directory and path.
+ *
+ * Hidden non-leaf function cost: 
+ * - calls strlcpy
+ * - calls find_last_slash()
+ * - calls strlcat
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_pathname_join_special(char *out_path,
+      const char *dir, const char *path, size_t size);
+
+size_t fill_pathname_join_special_ext(char *out_path,
+      const char *dir,  const char *path,
+      const char *last, const char *ext,
+      size_t size);
+
+/**
+ * fill_pathname_join_delim:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @delim              : delimiter
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together
+ * using the given delimiter (@delim).
+ *
+ * Hidden non-leaf function cost: 
+ * - can call strlen
+ * - can call strlcpy
+ * - can call strlcat
+ **/
+size_t fill_pathname_join_delim(char *out_path, const char *dir,
+      const char *path, const char delim, size_t size);
+
+size_t fill_pathname_expand_special(char *out_path,
+      const char *in_path, size_t size);
+
+size_t fill_pathname_abbreviate_special(char *out_path,
+      const char *in_path, size_t size);
+
+/**
+ * fill_pathname_abbreviated_or_relative:
+ *
+ * Fills the supplied path with either the abbreviated path or 
+ * the relative path, which ever one has less depth / number of slashes
+ * 
+ * If lengths of abbreviated and relative paths are the same,
+ * the relative path will be used
+ * @in_path can be an absolute, relative or abbreviated path
+ *
+ * @return Length of the string copied into @out_path
+ **/
+size_t fill_pathname_abbreviated_or_relative(char *out_path,
+               const char *in_refpath, const char *in_path, size_t size);
+
+/**
+ * pathname_conform_slashes_to_os:
+ *
+ * @path               : path
+ * 
+ * Leaf function.
+ *
+ * Changes the slashes to the correct kind for the os 
+ * So forward slash on linux and backslash on Windows
+ **/
+void pathname_conform_slashes_to_os(char *path);
+
+/**
+ * pathname_make_slashes_portable:
+ * @path               : path
+ *
+ * Leaf function.
+ *
+ * Change all slashes to forward so they are more 
+ * portable between Windows and Linux
+ **/
+void pathname_make_slashes_portable(char *path);
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir_wrapper(char *path);
+
+/**
+ * path_char_is_slash:
+ * @c                  : character
+ *
+ * Checks if character (@c) is a slash.
+ *
+ * @return true if character is a slash, otherwise false.
+ **/
+#ifdef _WIN32
+#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
+#else
+#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
+#endif
+
+/**
+ * path_default_slash and path_default_slash_c:
+ *
+ * Gets the default slash separator.
+ *
+ * @return default slash separator.
+ **/
+#ifdef _WIN32
+#define PATH_DEFAULT_SLASH() "\\"
+#define PATH_DEFAULT_SLASH_C() '\\'
+#else
+#define PATH_DEFAULT_SLASH() "/"
+#define PATH_DEFAULT_SLASH_C() '/'
+#endif
+
+/**
+ * fill_pathname_slash:
+ * @path               : path
+ * @size               : size of path
+ *
+ * Assumes path is a directory. Appends a slash
+ * if not already there.
+
+ * Hidden non-leaf function cost: 
+ * - calls find_last_slash()
+ *   - can call strlcat once if it returns false
+ * - calls strlen
+ **/
+void fill_pathname_slash(char *path, size_t size);
+
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+void fill_pathname_application_path(char *buf, size_t size);
+void fill_pathname_application_dir(char *buf, size_t size);
+void fill_pathname_home_dir(char *buf, size_t size);
+#endif
+
+/**
+ * path_mkdir:
+ * @dir                : directory
+ *
+ * Create directory on filesystem.
+ *
+ * Recursive function.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls strdup
+ * - Calls path_parent_dir()
+ * - Calls strcmp
+ * - Calls path_is_directory()
+ * - Calls path_mkdir()
+ *
+ * @return true if directory could be created, otherwise false.
+ **/
+bool path_mkdir(const char *dir);
+
+/**
+ * path_is_directory:
+ * @path               : path
+ *
+ * Checks if path is a directory.
+ *
+ * @return true if path is a directory, otherwise false.
+ */
+bool path_is_directory(const char *path);
+
+/* Time format strings with AM-PM designation require special
+ * handling due to platform dependence */
+void strftime_am_pm(char *s, size_t len, const char* format,
+      const void* timeptr);
+
+bool path_is_character_special(const char *path);
+
+int path_stat(const char *path);
+
+bool path_is_valid(const char *path);
+
+int32_t path_get_size(const char *path);
+
+bool is_path_accessible_using_standard_io(const char *path);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/file/nbio.h b/deps/libretro-common/include/file/nbio.h
new file mode 100644 (file)
index 0000000..cd9f13b
--- /dev/null
@@ -0,0 +1,124 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nbio.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_NBIO_H
+#define __LIBRETRO_SDK_NBIO_H
+
+#include <stddef.h>
+#include <boolean.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#ifndef NBIO_READ
+#define NBIO_READ   0
+#endif
+
+#ifndef NBIO_WRITE
+#define NBIO_WRITE  1
+#endif
+
+#ifndef NBIO_UPDATE
+#define NBIO_UPDATE 2
+#endif
+
+/* these two are blocking; nbio_iterate always returns true, but that operation (or something earlier) may take arbitrarily long */
+#ifndef BIO_READ
+#define BIO_READ    3
+#endif
+
+#ifndef BIO_WRITE
+#define BIO_WRITE   4
+#endif
+
+typedef struct nbio_intf
+{
+   void *(*open)(const char * filename, unsigned mode);
+
+   void (*begin_read)(void *data);
+
+   void (*begin_write)(void *data);
+
+   bool (*iterate)(void *data);
+
+   void (*resize)(void *data, size_t len);
+
+   void *(*get_ptr)(void *data, size_t* len);
+
+   void (*cancel)(void *data);
+
+   void (*free)(void *data);
+
+   /* Human readable string. */
+   const char *ident;
+} nbio_intf_t;
+
+/*
+ * Creates an nbio structure for performing the
+ * given operation on the given file.
+ */
+void *nbio_open(const char * filename, unsigned mode);
+
+/*
+ * Starts reading the given file. When done, it will be available in nbio_get_ptr.
+ * Can not be done if the structure was created with {N,}BIO_WRITE.
+ */
+void nbio_begin_read(void *data);
+
+/*
+ * Starts writing to the given file. Before this, you should've copied the data to nbio_get_ptr.
+ * Can not be done if the structure was created with {N,}BIO_READ.
+ */
+void nbio_begin_write(void *data);
+
+/*
+ * Performs part of the requested operation, or checks how it's going.
+ * When it returns true, it's done.
+ */
+bool nbio_iterate(void *data);
+
+/*
+ * Resizes the file up to the given size; cannot shrink.
+ * Can not be done if the structure was created with {N,}BIO_READ.
+ */
+void nbio_resize(void *data, size_t len);
+
+/*
+ * Returns a pointer to the file data. Writable only if structure was not created with {N,}BIO_READ.
+ * If any operation is in progress, the pointer will be NULL, but len will still be correct.
+ */
+void* nbio_get_ptr(void *data, size_t* len);
+
+/*
+ * Stops any pending operation, allowing the object to be freed.
+ */
+void nbio_cancel(void *data);
+
+/*
+ * Deletes the nbio structure and its associated pointer.
+ */
+void nbio_free(void *data);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/filters.h b/deps/libretro-common/include/filters.h
new file mode 100644 (file)
index 0000000..6ef9ace
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (filters.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_FILTERS_H
+#define _LIBRETRO_SDK_FILTERS_H
+
+/* for MSVC; should be benign under any circumstances */
+#define _USE_MATH_DEFINES
+
+#include <stdlib.h>
+#include <math.h>
+#include <retro_inline.h>
+#include <retro_math.h>
+
+/**
+ * sinc:
+ *
+ * Pure function.
+ **/
+static INLINE double sinc(double val)
+{
+   if (fabs(val) < 0.00001)
+      return 1.0;
+   return sin(val) / val;
+}
+
+/**
+ * paeth:
+ *
+ * Pure function.
+ * Paeth prediction filter.
+ **/
+static INLINE int paeth(int a, int b, int c)
+{
+   int p  = a + b - c;
+   int pa = abs(p - a);
+   int pb = abs(p - b);
+   int pc = abs(p - c);
+
+   if (pa <= pb && pa <= pc)
+      return a;
+   else if (pb <= pc)
+      return b;
+   return c;
+}
+
+/**
+ * besseli0:
+ *
+ * Pure function.
+ *
+ * Modified Bessel function of first order.
+ * Check Wiki for mathematical definition ...
+ **/
+static INLINE double besseli0(double x)
+{
+   int i;
+   double sum            = 0.0;
+   double factorial      = 1.0;
+   double factorial_mult = 0.0;
+   double x_pow          = 1.0;
+   double two_div_pow    = 1.0;
+   double x_sqr          = x * x;
+
+   /* Approximate. This is an infinite sum.
+    * Luckily, it converges rather fast. */
+   for (i = 0; i < 18; i++)
+   {
+      sum            += x_pow * two_div_pow / (factorial * factorial);
+      factorial_mult += 1.0;
+      x_pow          *= x_sqr;
+      two_div_pow    *= 0.25;
+      factorial      *= factorial_mult;
+   }
+
+   return sum;
+}
+
+static INLINE double kaiser_window_function(double index, double beta)
+{
+   return besseli0(beta * sqrtf(1 - index * index));
+}
+
+#endif
diff --git a/deps/libretro-common/include/formats/cdfs.h b/deps/libretro-common/include/formats/cdfs.h
new file mode 100644 (file)
index 0000000..ab4241e
--- /dev/null
@@ -0,0 +1,113 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (cdfs.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __RARCH_CDFS_H
+#define __RARCH_CDFS_H
+
+#include <streams/interface_stream.h>
+
+RETRO_BEGIN_DECLS
+
+/* these functions provide an interface for locating and reading files within a data track
+ * of a CD (following the ISO-9660 directory structure definition)
+ */
+
+typedef struct cdfs_track_t
+{
+   intfstream_t* stream;
+   unsigned int stream_sector_size;
+   unsigned int stream_sector_header_size;
+   unsigned int first_sector_offset;
+   unsigned int first_sector_index;
+} cdfs_track_t;
+
+typedef struct cdfs_file_t
+{
+   struct cdfs_track_t* track;
+   int first_sector;
+   int current_sector;
+   int sector_buffer_valid;
+   unsigned int current_sector_offset;
+   unsigned int size;
+   unsigned int pos;
+   uint8_t sector_buffer[2048];
+} cdfs_file_t;
+
+/* opens the specified file within the CD or virtual CD.
+ * if path is NULL, will open the raw CD (useful for 
+ * reading CD without having to worry about sector sizes,
+ * headers, or checksum data)
+ */
+int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* stream, const char* path);
+
+void cdfs_close_file(cdfs_file_t* file);
+
+int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len);
+
+int64_t cdfs_get_size(cdfs_file_t* file);
+
+int64_t cdfs_tell(cdfs_file_t* file);
+
+int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence);
+
+void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector);
+
+uint32_t cdfs_get_num_sectors(cdfs_file_t* file);
+
+uint32_t cdfs_get_first_sector(cdfs_file_t* file);
+
+/* opens the specified track in a CD or virtual CD file - the resulting stream should be passed to
+ * cdfs_open_file to get access to a file within the CD.
+ *
+ * supported files:
+ *   real CD - path will be in the form "cdrom://drive1.cue" or "cdrom://d:/drive.cue"
+ *   bin/cue - path will point to the cue file
+ *   chd     - path will point to the chd file
+ *
+ * for bin/cue files, the following storage modes are supported:
+ *   MODE2/2352
+ *   MODE1/2352
+ *   MODE1/2048 - untested
+ *   MODE2/2336 - untested
+ */
+cdfs_track_t* cdfs_open_track(const char* path, unsigned int track_index);
+
+/* opens the first data track in a CD or virtual CD file. see cdfs_open_track for supported file formats
+ */
+cdfs_track_t* cdfs_open_data_track(const char* path);
+
+/* opens a raw track file for a CD or virtual CD.
+ *
+ * supported files:
+ *   real CD - path will be in the form "cdrom://drive1-track01.bin" or "cdrom://d:/drive-track01.bin"
+ *             NOTE: cue file for CD must be opened first to populate vfs_cdrom_toc.
+ *   bin     - path will point to the bin file
+ *   iso     - path will point to the iso file
+ */
+cdfs_track_t* cdfs_open_raw_track(const char* path);
+
+/* closes the CD or virtual CD track and frees the associated memory */
+void cdfs_close_track(cdfs_track_t* track);
+
+RETRO_END_DECLS
+
+#endif /* __RARCH_CDFS_H */
diff --git a/deps/libretro-common/include/formats/image.h b/deps/libretro-common/include/formats/image.h
new file mode 100644 (file)
index 0000000..70e5842
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (image.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __RARCH_IMAGE_CONTEXT_H
+#define __RARCH_IMAGE_CONTEXT_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+enum image_process_code
+{
+   IMAGE_PROCESS_ERROR     = -2,
+   IMAGE_PROCESS_ERROR_END = -1,
+   IMAGE_PROCESS_NEXT      =  0,
+   IMAGE_PROCESS_END       =  1
+};
+
+struct texture_image
+{
+   uint32_t *pixels;
+   unsigned width;
+   unsigned height;
+   bool supports_rgba;
+};
+
+enum image_type_enum
+{
+   IMAGE_TYPE_NONE = 0,
+   IMAGE_TYPE_PNG,
+   IMAGE_TYPE_JPEG,
+   IMAGE_TYPE_BMP,
+   IMAGE_TYPE_TGA
+};
+
+enum image_type_enum image_texture_get_type(const char *path);
+
+bool image_texture_set_color_shifts(unsigned *r_shift, unsigned *g_shift,
+      unsigned *b_shift, unsigned *a_shift,
+      struct texture_image *out_img);
+
+bool image_texture_color_convert(unsigned r_shift,
+      unsigned g_shift, unsigned b_shift, unsigned a_shift,
+      struct texture_image *out_img);
+
+bool image_texture_load_buffer(struct texture_image *img,
+   enum image_type_enum type, void *buffer, size_t buffer_len);
+
+bool image_texture_load(struct texture_image *img, const char *path);
+void image_texture_free(struct texture_image *img);
+
+/* Image transfer */
+
+void image_transfer_free(void *data, enum image_type_enum type);
+
+void *image_transfer_new(enum image_type_enum type);
+
+bool image_transfer_start(void *data, enum image_type_enum type);
+
+void image_transfer_set_buffer_ptr(
+      void *data,
+      enum image_type_enum type,
+      void *ptr,
+      size_t len);
+
+int image_transfer_process(
+      void *data,
+      enum image_type_enum type,
+      uint32_t **buf, size_t size,
+      unsigned *width, unsigned *height);
+
+bool image_transfer_iterate(void *data, enum image_type_enum type);
+
+bool image_transfer_is_valid(void *data, enum image_type_enum type);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/logiqx_dat.h b/deps/libretro-common/include/formats/logiqx_dat.h
new file mode 100644 (file)
index 0000000..fc7b64a
--- /dev/null
@@ -0,0 +1,107 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (logiqx_dat.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__
+#define __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__
+
+#include <retro_common_api.h>
+#include <retro_miscellaneous.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+/* Trivial handler for DAT files in Logiqx XML format
+ * (http://www.logiqx.com/). Provides bare minimum
+ * functionality - predominantly concerned with obtaining
+ * description text for specific arcade ROM images.
+ *
+ * Note: Also supports the following alternative DAT
+ * formats, since they are functionally identical to
+ * Logiqx XML (but with different element names):
+ * > MAME List XML
+ * > MAME 'Software List' */
+
+/* Prevent direct access to logiqx_dat_t members */
+typedef struct logiqx_dat logiqx_dat_t;
+
+/* Holds all metadata for a single game entry
+ * in the DAT file (minimal at present - may be
+ * expanded with individual internal ROM data
+ * if required) */
+typedef struct
+{
+   char name[PATH_MAX_LENGTH];
+   char description[PATH_MAX_LENGTH];
+   char year[8];
+   char manufacturer[128];
+   bool is_bios;
+   bool is_runnable;
+} logiqx_dat_game_info_t;
+
+/* Validation */
+
+/* Performs rudimentary validation of the specified
+ * Logiqx XML DAT file path (not rigorous - just
+ * enough to prevent obvious errors).
+ * Also provides access to file size (DAT files can
+ * be very large, so it is useful to have this information
+ * on hand - i.e. so we can check that the system has
+ * enough free memory to load the file). */ 
+bool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size);
+
+/* File initialisation/de-initialisation */
+
+/* Loads specified Logiqx XML DAT file from disk.
+ * Returned logiqx_dat_t object must be free'd using
+ * logiqx_dat_free().
+ * Returns NULL if file is invalid or a read error
+ * occurs. */
+logiqx_dat_t *logiqx_dat_init(const char *path);
+
+/* Frees specified DAT file */
+void logiqx_dat_free(logiqx_dat_t *dat_file);
+
+/* Game information access */
+
+/* Sets/resets internal node pointer to the first
+ * entry in the DAT file */
+void logiqx_dat_set_first(logiqx_dat_t *dat_file);
+
+/* Fetches game information for the current entry
+ * in the DAT file and increments the internal node
+ * pointer.
+ * Returns false if the end of the DAT file has been
+ * reached (in which case 'game_info' will be invalid) */
+bool logiqx_dat_get_next(
+      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info);
+
+/* Fetches information for the specified game.
+ * Returns false if game does not exist, or arguments
+ * are invalid. */
+bool logiqx_dat_search(
+      logiqx_dat_t *dat_file, const char *game_name,
+      logiqx_dat_game_info_t *game_info);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/m3u_file.h b/deps/libretro-common/include/formats/m3u_file.h
new file mode 100644 (file)
index 0000000..83a1625
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (m3u_file.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_M3U_FILE_H__
+#define __LIBRETRO_SDK_FORMAT_M3U_FILE_H__
+
+#include <retro_common_api.h>
+
+#include <stdint.h>
+#include <stddef.h>
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+/* Trivial handler for M3U playlist files */
+
+/* M3U file extension */
+#define M3U_FILE_EXT "m3u"
+
+/* Prevent direct access to m3u_file_t members */
+typedef struct content_m3u_file m3u_file_t;
+
+/* Holds all metadata for a single M3U file entry */
+typedef struct
+{
+   char *path;
+   char *full_path;
+   char *label;
+} m3u_file_entry_t;
+
+/* Defines entry label formatting when
+ * writing M3U files to disk */
+enum m3u_file_label_type
+{
+   M3U_FILE_LABEL_NONE = 0,
+   M3U_FILE_LABEL_NONSTD,
+   M3U_FILE_LABEL_EXTSTD,
+   M3U_FILE_LABEL_RETRO
+};
+
+/* File Initialisation / De-Initialisation */
+
+/* Creates and initialises an M3U file
+ * - If 'path' refers to an existing file,
+ *   contents is parsed
+ * - If path does not exist, an empty M3U file
+ *   is created
+ * - Returned m3u_file_t object must be free'd using
+ *   m3u_file_free()
+ * - Returns NULL in the event of an error */
+m3u_file_t *m3u_file_init(const char *path);
+
+/* Frees specified M3U file */
+void m3u_file_free(m3u_file_t *m3u_file);
+
+/* Getters */
+
+/* Returns M3U file path */
+char *m3u_file_get_path(m3u_file_t *m3u_file);
+
+/* Returns number of entries in M3U file */
+size_t m3u_file_get_size(m3u_file_t *m3u_file);
+
+/* Fetches specified M3U file entry
+ * - Returns false if 'idx' is invalid, or internal
+ *   entry is NULL */
+bool m3u_file_get_entry(
+      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry);
+
+/* Setters */
+
+/* Adds specified entry to the M3U file
+ * - Returns false if path is invalid, or
+ *   memory could not be allocated for the
+ *   entry */
+bool m3u_file_add_entry(
+      m3u_file_t *m3u_file, const char *path, const char *label);
+
+/* Removes all entries in M3U file */
+void m3u_file_clear(m3u_file_t *m3u_file);
+
+/* Saving */
+
+/* Saves M3U file to disk
+ * - Setting 'label_type' to M3U_FILE_LABEL_NONE
+ *   just outputs entry paths - this the most
+ *   common format supported by most cores
+ * - Returns false in the event of an error */
+bool m3u_file_save(
+      m3u_file_t *m3u_file, enum m3u_file_label_type label_type);
+
+/* Utilities */
+
+/* Sorts M3U file entries in alphabetical order */
+void m3u_file_qsort(m3u_file_t *m3u_file);
+
+/* Returns true if specified path corresponds
+ * to an M3U file (simple convenience function) */
+bool m3u_file_is_m3u(const char *path);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rbmp.h b/deps/libretro-common/include/formats/rbmp.h
new file mode 100644 (file)
index 0000000..6e20df0
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rbmp.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RBMP_H__
+#define __LIBRETRO_SDK_FORMAT_RBMP_H__
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+enum rbmp_source_type
+{
+   RBMP_SOURCE_TYPE_DONT_CARE,
+   RBMP_SOURCE_TYPE_BGR24,
+   RBMP_SOURCE_TYPE_XRGB888,
+   RBMP_SOURCE_TYPE_RGB565,
+   RBMP_SOURCE_TYPE_ARGB8888
+};
+
+typedef struct rbmp rbmp_t;
+
+bool rbmp_save_image(
+      const char *filename,
+      const void *frame,
+      unsigned width,
+      unsigned height,
+      unsigned pitch,
+      enum rbmp_source_type type);
+
+int rbmp_process_image(rbmp_t *rbmp, void **buf,
+      size_t size, unsigned *width, unsigned *height);
+
+void form_bmp_header(uint8_t *header,
+      unsigned width, unsigned height,
+      bool is32bpp);
+
+bool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data);
+
+void rbmp_free(rbmp_t *rbmp);
+
+rbmp_t *rbmp_alloc(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rjpeg.h b/deps/libretro-common/include/formats/rjpeg.h
new file mode 100644 (file)
index 0000000..18d3568
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rjpeg.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RJPEG_H__
+#define __LIBRETRO_SDK_FORMAT_RJPEG_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct rjpeg rjpeg_t;
+
+int rjpeg_process_image(rjpeg_t *rjpeg, void **buf,
+      size_t size, unsigned *width, unsigned *height);
+
+bool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data);
+
+void rjpeg_free(rjpeg_t *rjpeg);
+
+rjpeg_t *rjpeg_alloc(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rjson.h b/deps/libretro-common/include/formats/rjson.h
new file mode 100644 (file)
index 0000000..0261c71
--- /dev/null
@@ -0,0 +1,242 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rjson.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RJSON_H__
+#define __LIBRETRO_SDK_FORMAT_RJSON_H__
+
+#include <retro_common_api.h>
+#include <boolean.h> /* bool */
+#include <stddef.h> /* size_t */
+
+RETRO_BEGIN_DECLS
+
+/* List of possible element types returned by rjson_next */
+enum rjson_type
+{
+   RJSON_DONE,
+   RJSON_OBJECT, RJSON_ARRAY, RJSON_OBJECT_END, RJSON_ARRAY_END,
+   RJSON_STRING, RJSON_NUMBER, RJSON_TRUE, RJSON_FALSE, RJSON_NULL,
+   RJSON_ERROR
+};
+
+/* Options that can be passed to rjson_set_options */
+enum rjson_option
+{
+   /* Allow UTF-8 byte order marks */
+   RJSON_OPTION_ALLOW_UTF8BOM                      = (1<<0),
+   /* Allow JavaScript style comments in the stream */
+   RJSON_OPTION_ALLOW_COMMENTS                     = (1<<1),
+   /* Allow unescaped control characters in strings (bytes 0x00 - 0x1F) */
+   RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS = (1<<2),
+   /* Ignore invalid Unicode escapes and don't validate UTF-8 codes */
+   RJSON_OPTION_IGNORE_INVALID_ENCODING            = (1<<3),
+   /* Replace invalid Unicode escapes and UTF-8 codes with a '?' character */
+   RJSON_OPTION_REPLACE_INVALID_ENCODING           = (1<<4),
+   /* Ignore carriage return (\r escape sequence) in strings */
+   RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN      = (1<<5),
+   /* Allow data after the end of the top JSON object/array/value */
+   RJSON_OPTION_ALLOW_TRAILING_DATA                = (1<<6)
+};
+
+/* Custom data input callback
+ * Should return > 0 and <= len on success, 0 on file end and < 0 on error. */
+typedef int (*rjson_io_t)(void* buf, int len, void *user_data);
+typedef struct rjson rjson_t;
+struct intfstream_internal;
+struct RFILE;
+
+/* Create a new parser instance from various sources */
+rjson_t *rjson_open_stream(struct intfstream_internal *stream);
+rjson_t *rjson_open_rfile(struct RFILE *rfile);
+rjson_t *rjson_open_buffer(const void *buffer, size_t size);
+rjson_t *rjson_open_string(const char *string, size_t len);
+rjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size);
+
+/* Free the parser instance created with rjson_open_* */
+void rjson_free(rjson_t *json);
+
+/* Set one or more enum rjson_option, will override previously set options.
+ * Use bitwise OR to concatenate multiple options.
+ * By default none of the options are set. */
+void rjson_set_options(rjson_t *json, char rjson_option_flags);
+
+/* Sets the maximum context depth, recursion inside arrays and objects.
+ * By default this is set to 50. */
+void rjson_set_max_depth(rjson_t *json, unsigned int max_depth);
+
+/* Parse to the next JSON element and return the type of it.
+ * Will return RJSON_DONE when successfully reaching the end or
+ * RJSON_ERROR when an error was encountered. */
+enum rjson_type rjson_next(rjson_t *json);
+
+/* Get the current string, null-terminated unescaped UTF-8 encoded.
+ * Can only be used when the current element is RJSON_STRING or RJSON_NUMBER.
+ * The returned pointer is only valid until the parsing continues. */
+const char *rjson_get_string(rjson_t *json, size_t *length);
+
+/* Returns the current number (or string) converted to double or int */
+double rjson_get_double(rjson_t *json);
+int    rjson_get_int(rjson_t *json);
+
+/* Returns a string describing the error once rjson_next/rjson_parse
+ * has returned an unrecoverable RJSON_ERROR (otherwise returns ""). */
+const char *rjson_get_error(rjson_t *json);
+
+/* Can be used to set a custom error description on an invalid JSON structure.
+ * Maximum length of 79 characters and once set the parsing can't continue. */
+void rjson_set_error(rjson_t *json, const char* error);
+
+/* Functions to get the current position in the source stream as well as */
+/* a bit of source json arround the current position for additional detail
+ * when parsing has failed with RJSON_ERROR.
+ * Intended to be used with printf style formatting like:
+ * printf("Invalid JSON at line %d, column %d - %s - Source: ...%.*s...\n",
+ *       (int)rjson_get_source_line(json), (int)rjson_get_source_column(json),
+ *       rjson_get_error(json), rjson_get_source_context_len(json),
+ *       rjson_get_source_context_buf(json)); */
+size_t      rjson_get_source_line(rjson_t *json);
+size_t      rjson_get_source_column(rjson_t *json);
+int         rjson_get_source_context_len(rjson_t *json);
+const char* rjson_get_source_context_buf(rjson_t *json);
+
+/* Confirm the parsing context stack, for example calling
+   rjson_check_context(json, 2, RJSON_OBJECT, RJSON_ARRAY)
+   returns true when inside "{ [ ..." but not for "[ .." or "{ [ { ..." */
+bool rjson_check_context(rjson_t *json, unsigned int depth, ...);
+
+/* Returns the current level of nested objects/arrays */
+unsigned int rjson_get_context_depth(rjson_t *json);
+
+/* Return the current parsing context, that is, RJSON_OBJECT if we are inside
+ * an object, RJSON_ARRAY if we are inside an array, and RJSON_DONE or 
+ * RJSON_ERROR if we are not yet/anymore in either. */
+enum rjson_type rjson_get_context_type(rjson_t *json);
+
+/* While inside an object or an array, this return the number of parsing
+ * events that have already been observed at this level with rjson_next.
+ * In particular, inside an object, an odd number would indicate that the just
+ * observed RJSON_STRING event is a member name. */
+size_t rjson_get_context_count(rjson_t *json);
+
+/* Parse an entire JSON stream with a list of element specific handlers.
+ * Each of the handlers can be passed a function or NULL to ignore it.
+ * If a handler returns false, the parsing will abort and the returned
+ * rjson_type will indicate on which element type parsing was aborted.
+ * Otherwise the return value will be RJSON_DONE or RJSON_ERROR. */
+enum rjson_type rjson_parse(rjson_t *json, void* context,
+      bool (*object_member_handler)(void *context, const char *str, size_t len),
+      bool (*string_handler       )(void *context, const char *str, size_t len),
+      bool (*number_handler       )(void *context, const char *str, size_t len),
+      bool (*start_object_handler )(void *context),
+      bool (*end_object_handler   )(void *context),
+      bool (*start_array_handler  )(void *context),
+      bool (*end_array_handler    )(void *context),
+      bool (*boolean_handler      )(void *context, bool value),
+      bool (*null_handler         )(void *context));
+
+/* A simpler interface to parse a JSON in memory. This will avoid any memory
+ * allocations unless the document contains strings longer than 512 characters.
+ * In the error handler, error will be "" if any of the other handlers aborted. */
+bool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,
+      bool (*object_member_handler)(void *context, const char *str, size_t len),
+      bool (*string_handler       )(void *context, const char *str, size_t len),
+      bool (*number_handler       )(void *context, const char *str, size_t len),
+      bool (*start_object_handler )(void *context),
+      bool (*end_object_handler   )(void *context),
+      bool (*start_array_handler  )(void *context),
+      bool (*end_array_handler    )(void *context),
+      bool (*boolean_handler      )(void *context, bool value),
+      bool (*null_handler         )(void *context),
+      void (*error_handler        )(void *context, int line, int col, const char* error));
+
+/* ------------------------------------------------------------------------- */
+
+/* Options that can be passed to rjsonwriter_set_options */
+enum rjsonwriter_option
+{
+   /* Don't write spaces, tabs or newlines to the output (except in strings) */
+   RJSONWRITER_OPTION_SKIP_WHITESPACE = (1<<0)
+};
+
+/* Custom data output callback
+ * Should return len on success and < len on a write error. */
+typedef int (*rjsonwriter_io_t)(const void* buf, int len, void *user_data);
+typedef struct rjsonwriter rjsonwriter_t;
+
+/* Create a new writer instance to various targets */
+rjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream);
+rjsonwriter_t *rjsonwriter_open_rfile(struct RFILE *rfile);
+rjsonwriter_t *rjsonwriter_open_memory(void);
+rjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data);
+
+/* When opened with rjsonwriter_open_memory, will return the generated JSON.
+ * Result is always null-terminated. Passed len can be NULL if not needed,
+ * otherwise returned len will be string length without null-terminator.
+ * Returns NULL if writing ran out of memory or not opened from memory.
+ * Returned buffer is only valid until writer is modified or freed. */
+char* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len);
+
+/* When opened with rjsonwriter_open_memory, will return current length */
+int rjsonwriter_count_memory_buffer(rjsonwriter_t *writer);
+
+/* When opened with rjsonwriter_open_memory, will clear the buffer.
+   The buffer will be partially erased if keep_len is > 0.
+   No memory is freed or re-allocated with this function. */
+void rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len);
+
+/* Free rjsonwriter handle and return result of final rjsonwriter_flush call */
+bool rjsonwriter_free(rjsonwriter_t *writer);
+
+/* Set one or more enum rjsonwriter_option, will override previously set options.
+ * Use bitwise OR to concatenate multiple options.
+ * By default none of the options are set. */
+void rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags);
+
+/* Flush any buffered output data to the output stream.
+ * Returns true if the data was successfully written. Once writing fails once,
+ * no more data will be written and flush will always returns false */
+bool rjsonwriter_flush(rjsonwriter_t *writer);
+
+/* Returns a string describing an error or "" if there was none.
+ * The only error possible is "output error" after the io function failed.
+ * If rjsonwriter_rawf were used manually, "out of memory" is also possible. */
+const char *rjsonwriter_get_error(rjsonwriter_t *writer);
+
+/* Used by the inline functions below to append raw data */
+void rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len);
+void rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...);
+
+/* Add a UTF-8 encoded string
+ * Special and control characters are automatically escaped.
+ * If NULL is passed an empty string will be written (not JSON null). */
+void rjsonwriter_add_string(rjsonwriter_t *writer, const char *value);
+void rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len);
+
+void rjsonwriter_add_double(rjsonwriter_t *writer, double value);
+
+void rjsonwriter_add_spaces(rjsonwriter_t *writer, int count);
+
+void rjsonwriter_add_tabs(rjsonwriter_t *writer, int count);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rjson_helpers.h b/deps/libretro-common/include/formats/rjson_helpers.h
new file mode 100644 (file)
index 0000000..01f2589
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rjson.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__
+#define __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__
+
+#include <retro_common_api.h>
+#include <retro_inline.h> /* INLINE */
+#include <boolean.h> /* bool */
+#include <stddef.h> /* size_t */
+
+RETRO_BEGIN_DECLS
+
+/* Functions to add JSON token characters */
+static INLINE void rjsonwriter_add_start_object(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, "{", 1); }
+
+static INLINE void rjsonwriter_add_end_object(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, "}", 1); }
+
+static INLINE void rjsonwriter_add_start_array(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, "[", 1); }
+
+static INLINE void rjsonwriter_add_end_array(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, "]", 1); }
+
+static INLINE void rjsonwriter_add_colon(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, ":", 1); }
+
+static INLINE void rjsonwriter_add_comma(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, ",", 1); }
+
+/* Functions to add whitespace characters */
+/* These do nothing with the option RJSONWRITER_OPTION_SKIP_WHITESPACE */
+static INLINE void rjsonwriter_add_newline(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, "\n", 1); }
+
+static INLINE void rjsonwriter_add_space(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, " ", 1); }
+
+static INLINE void rjsonwriter_add_tab(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, "\t", 1); }
+
+static INLINE void rjsonwriter_add_unsigned(rjsonwriter_t *writer, unsigned value)
+      { rjsonwriter_rawf(writer, "%u", value); }
+
+/* Add a signed or unsigned integer or a double number */
+static INLINE void rjsonwriter_add_int(rjsonwriter_t *writer, int value)
+      { rjsonwriter_rawf(writer, "%d", value); }
+
+static INLINE void rjsonwriter_add_bool(rjsonwriter_t *writer, bool value)
+      { rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5)); }
+
+static INLINE void rjsonwriter_add_null(rjsonwriter_t *writer)
+      { rjsonwriter_raw(writer, "null", 4); }
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rpng.h b/deps/libretro-common/include/formats/rpng.h
new file mode 100644 (file)
index 0000000..d855658
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rpng.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RPNG_H__
+#define __LIBRETRO_SDK_FORMAT_RPNG_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct rpng rpng_t;
+
+rpng_t *rpng_init(const char *path);
+
+bool rpng_is_valid(rpng_t *rpng);
+
+bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len);
+
+rpng_t *rpng_alloc(void);
+
+void rpng_free(rpng_t *rpng);
+
+bool rpng_iterate_image(rpng_t *rpng);
+
+int rpng_process_image(rpng_t *rpng,
+      void **data, size_t size, unsigned *width, unsigned *height);
+
+bool rpng_start(rpng_t *rpng);
+
+bool rpng_save_image_argb(const char *path, const uint32_t *data,
+      unsigned width, unsigned height, unsigned pitch);
+bool rpng_save_image_bgr24(const char *path, const uint8_t *data,
+      unsigned width, unsigned height, unsigned pitch);
+
+uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
+      unsigned width, unsigned height, signed pitch, uint64_t *bytes);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rtga.h b/deps/libretro-common/include/formats/rtga.h
new file mode 100644 (file)
index 0000000..330e471
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rtga.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RTGA_H__
+#define __LIBRETRO_SDK_FORMAT_RTGA_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct rtga rtga_t;
+
+int rtga_process_image(rtga_t *rtga, void **buf,
+      size_t size, unsigned *width, unsigned *height);
+
+bool rtga_set_buf_ptr(rtga_t *rtga, void *data);
+
+void rtga_free(rtga_t *rtga);
+
+rtga_t *rtga_alloc(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rwav.h b/deps/libretro-common/include/formats/rwav.h
new file mode 100644 (file)
index 0000000..e5379da
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rwav.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RWAV_H__
+#define __LIBRETRO_SDK_FORMAT_RWAV_H__
+
+#include <retro_common_api.h>
+#include <stdint.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct
+{
+   /* bits per sample */
+   unsigned int bitspersample;
+
+   /* number of channels */
+   unsigned int numchannels;
+
+   /* sample rate */
+   unsigned int samplerate;
+
+   /* number of *samples* */
+   size_t numsamples;
+
+   /* number of *bytes* in the pointer below, i.e. numsamples * numchannels * bitspersample/8 */
+   size_t subchunk2size;
+
+   /* PCM data */
+   const void* samples;
+} rwav_t;
+
+enum rwav_state
+{
+   RWAV_ITERATE_ERROR    = -1,
+   RWAV_ITERATE_MORE     = 0,
+   RWAV_ITERATE_DONE     = 1,
+   RWAV_ITERATE_BUF_SIZE = 4096
+};
+
+typedef struct rwav_iterator rwav_iterator_t;
+
+/**
+ * Initializes the iterator to fill the out structure with data parsed from buf.
+ */
+void rwav_init(rwav_iterator_t* iter, rwav_t* out, const void* buf, size_t size);
+
+/**
+ * Parses a piece of the data. Continue calling as long as it returns RWAV_ITERATE_MORE.
+ * Stop calling otherwise, and check for errors. If RWAV_ITERATE_DONE is returned,
+ * the rwav_t structure passed to rwav_init is ready to be used. The iterator does not
+ * have to be freed.
+ */
+enum rwav_state rwav_iterate(rwav_iterator_t *iter);
+
+/**
+ * Loads the entire data in one go.
+ */
+enum rwav_state rwav_load(rwav_t* out, const void* buf, size_t size);
+
+/**
+ * Frees parsed wave data.
+ */
+void rwav_free(rwav_t *rwav);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/formats/rxml.h b/deps/libretro-common/include/formats/rxml.h
new file mode 100644 (file)
index 0000000..e3f1c9a
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rxml.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FORMAT_RXML_H__
+#define __LIBRETRO_SDK_FORMAT_RXML_H__
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/* Total NIH. Very trivial "XML" implementation for use in RetroArch.
+ * Error checking is minimal. Invalid documents may lead to very
+ * buggy behavior, but memory corruption should never happen.
+ *
+ * Only parts of standard that RetroArch cares about is supported.
+ * Nothing more, nothing less. "Clever" XML documents will
+ * probably break the implementation.
+ *
+ * Do *NOT* try to use this for anything else. You have been warned.
+ */
+
+typedef struct rxml_document rxml_document_t;
+
+struct rxml_attrib_node
+{
+   char *attrib;
+   char *value;
+   struct rxml_attrib_node *next;
+};
+
+typedef struct rxml_node
+{
+   char *name;
+   char *data;
+   struct rxml_attrib_node *attrib;
+
+   struct rxml_node *children;
+   struct rxml_node *next;
+} rxml_node_t;
+
+rxml_document_t *rxml_load_document(const char *path);
+rxml_document_t *rxml_load_document_string(const char *str);
+void rxml_free_document(rxml_document_t *doc);
+
+struct rxml_node *rxml_root_node(rxml_document_t *doc);
+
+const char *rxml_node_attrib(struct rxml_node *node, const char *attrib);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/gl_capabilities.h b/deps/libretro-common/include/gfx/gl_capabilities.h
new file mode 100644 (file)
index 0000000..fc6c17c
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (gl_capabilities.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _GL_CAPABILITIES_H
+#define _GL_CAPABILITIES_H
+
+#include <boolean.h>
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+enum gl_capability_enum
+{
+   GL_CAPS_NONE = 0,
+   GL_CAPS_EGLIMAGE,
+   GL_CAPS_SYNC,
+   GL_CAPS_MIPMAP,
+   GL_CAPS_VAO,
+   GL_CAPS_FBO,
+   GL_CAPS_ARGB8,
+   GL_CAPS_DEBUG,
+   GL_CAPS_PACKED_DEPTH_STENCIL,
+   GL_CAPS_ES2_COMPAT,
+   GL_CAPS_UNPACK_ROW_LENGTH,
+   GL_CAPS_FULL_NPOT_SUPPORT,
+   GL_CAPS_SRGB_FBO,
+   GL_CAPS_SRGB_FBO_ES3,
+   GL_CAPS_FP_FBO,
+   GL_CAPS_BGRA8888,
+   GL_CAPS_GLES3_SUPPORTED,
+   GL_CAPS_TEX_STORAGE,
+   GL_CAPS_TEX_STORAGE_EXT
+};
+
+bool gl_query_core_context_in_use(void);
+
+void gl_query_core_context_set(bool set);
+
+void gl_query_core_context_unset(void);
+
+bool gl_query_extension(const char *ext);
+
+bool gl_check_error(char **error_string);
+
+bool gl_check_capability(enum gl_capability_enum enum_idx);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/math/matrix_3x3.h b/deps/libretro-common/include/gfx/math/matrix_3x3.h
new file mode 100644 (file)
index 0000000..2e0bcf5
--- /dev/null
@@ -0,0 +1,253 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (matrix_3x3.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__
+#define __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__
+
+#include <boolean.h>
+#include <math.h>
+#include <string.h>
+
+#include <retro_common_api.h>
+#include <retro_inline.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct math_matrix_3x3
+{
+   float data[9];
+} math_matrix_3x3;
+
+#define MAT_ELEM_3X3(mat, r, c) ((mat).data[3 * (r) + (c)])
+
+#define matrix_3x3_init(mat, n11, n12, n13, n21, n22, n23, n31, n32, n33) \
+   MAT_ELEM_3X3(mat, 0, 0) = n11; \
+   MAT_ELEM_3X3(mat, 0, 1) = n12; \
+   MAT_ELEM_3X3(mat, 0, 2) = n13; \
+   MAT_ELEM_3X3(mat, 1, 0) = n21; \
+   MAT_ELEM_3X3(mat, 1, 1) = n22; \
+   MAT_ELEM_3X3(mat, 1, 2) = n23; \
+   MAT_ELEM_3X3(mat, 2, 0) = n31; \
+   MAT_ELEM_3X3(mat, 2, 1) = n32; \
+   MAT_ELEM_3X3(mat, 2, 2) = n33
+
+#define matrix_3x3_identity(mat) \
+   MAT_ELEM_3X3(mat, 0, 0) = 1.0f; \
+   MAT_ELEM_3X3(mat, 0, 1) = 0; \
+   MAT_ELEM_3X3(mat, 0, 2) = 0; \
+   MAT_ELEM_3X3(mat, 1, 0) = 0; \
+   MAT_ELEM_3X3(mat, 1, 1) = 1.0f; \
+   MAT_ELEM_3X3(mat, 1, 2) = 0; \
+   MAT_ELEM_3X3(mat, 2, 0) = 0; \
+   MAT_ELEM_3X3(mat, 2, 1) = 0; \
+   MAT_ELEM_3X3(mat, 2, 2) = 1.0f
+
+#define matrix_3x3_divide_scalar(mat, s) \
+   MAT_ELEM_3X3(mat, 0, 0) /= s; \
+   MAT_ELEM_3X3(mat, 0, 1) /= s; \
+   MAT_ELEM_3X3(mat, 0, 2) /= s; \
+   MAT_ELEM_3X3(mat, 1, 0) /= s; \
+   MAT_ELEM_3X3(mat, 1, 1) /= s; \
+   MAT_ELEM_3X3(mat, 1, 2) /= s; \
+   MAT_ELEM_3X3(mat, 2, 0) /= s; \
+   MAT_ELEM_3X3(mat, 2, 1) /= s; \
+   MAT_ELEM_3X3(mat, 2, 2) /= s
+
+#define matrix_3x3_transpose(mat, in) \
+   MAT_ELEM_3X3(mat, 0, 0) = MAT_ELEM_3X3(in, 0, 0); \
+   MAT_ELEM_3X3(mat, 1, 0) = MAT_ELEM_3X3(in, 0, 1); \
+   MAT_ELEM_3X3(mat, 2, 0) = MAT_ELEM_3X3(in, 0, 2); \
+   MAT_ELEM_3X3(mat, 0, 1) = MAT_ELEM_3X3(in, 1, 0); \
+   MAT_ELEM_3X3(mat, 1, 1) = MAT_ELEM_3X3(in, 1, 1); \
+   MAT_ELEM_3X3(mat, 2, 1) = MAT_ELEM_3X3(in, 1, 2); \
+   MAT_ELEM_3X3(mat, 0, 2) = MAT_ELEM_3X3(in, 2, 0); \
+   MAT_ELEM_3X3(mat, 1, 2) = MAT_ELEM_3X3(in, 2, 1); \
+   MAT_ELEM_3X3(mat, 2, 2) = MAT_ELEM_3X3(in, 2, 2)
+
+#define matrix_3x3_multiply(out, a, b) \
+   MAT_ELEM_3X3(out, 0, 0) =  \
+      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 0) + \
+      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 0) + \
+      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 0); \
+   MAT_ELEM_3X3(out, 0, 1) = \
+      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 1) + \
+      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 1) + \
+      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 1); \
+   MAT_ELEM_3X3(out, 0, 2) = \
+      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 2) + \
+      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 2) + \
+      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 2); \
+   MAT_ELEM_3X3(out, 1, 0) = \
+      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 0) + \
+      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 0) + \
+      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 0); \
+   MAT_ELEM_3X3(out, 1, 1) =  \
+      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 1) + \
+      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 1) + \
+      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 1); \
+   MAT_ELEM_3X3(out, 1, 2) = \
+      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 2) + \
+      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 2) + \
+      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 2); \
+   MAT_ELEM_3X3(out, 2, 0) =  \
+      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 0) + \
+      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 0) + \
+      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 0); \
+   MAT_ELEM_3X3(out, 2, 1) = \
+      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 1) + \
+      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 1) + \
+      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 1); \
+   MAT_ELEM_3X3(out, 2, 2) =  \
+      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 2) + \
+      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 2) + \
+      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 2)
+
+#define matrix_3x3_determinant(mat) (MAT_ELEM_3X3(mat, 0, 0) * (MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 1)) - MAT_ELEM_3X3(mat, 0, 1) * (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 0)) + MAT_ELEM_3X3(mat, 0, 2) * (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 0)))
+
+#define matrix_3x3_adjoint(mat) \
+   MAT_ELEM_3X3(mat, 0, 0) =  (MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 1)); \
+   MAT_ELEM_3X3(mat, 0, 1) = -(MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 2, 1)); \
+   MAT_ELEM_3X3(mat, 0, 2) =  (MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 1, 1) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 1, 1)); \
+   MAT_ELEM_3X3(mat, 1, 0) = -(MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 1, 2) * MAT_ELEM_3X3(mat, 2, 0)); \
+   MAT_ELEM_3X3(mat, 1, 1) =  (MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 2, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 2, 0)); \
+   MAT_ELEM_3X3(mat, 1, 2) = -(MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 1, 2) - MAT_ELEM_3X3(mat, 0, 2) * MAT_ELEM_3X3(mat, 1, 0)); \
+   MAT_ELEM_3X3(mat, 2, 0) =  (MAT_ELEM_3X3(mat, 1, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 1, 1) * MAT_ELEM_3X3(mat, 2, 0)); \
+   MAT_ELEM_3X3(mat, 2, 1) = -(MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 2, 1) - MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 2, 0)); \
+   MAT_ELEM_3X3(mat, 2, 2) =  (MAT_ELEM_3X3(mat, 0, 0) * MAT_ELEM_3X3(mat, 1, 1) - MAT_ELEM_3X3(mat, 0, 1) * MAT_ELEM_3X3(mat, 1, 0))
+
+#define FLOATS_ARE_EQUAL(x, y)  (fabs(x - y) <= 0.00001f * ((x) > (y) ? (y) : (x)))
+#define FLOAT_IS_ZERO(x)        (FLOATS_ARE_EQUAL((x) + 1, 1))
+
+static INLINE bool matrix_3x3_invert(math_matrix_3x3 *mat)
+{
+   float det = matrix_3x3_determinant(*mat);
+
+   if (FLOAT_IS_ZERO(det))
+      return false;
+
+   matrix_3x3_adjoint(*mat);
+   matrix_3x3_divide_scalar(*mat, det);
+
+   return true;
+}
+
+static INLINE bool matrix_3x3_square_to_quad(
+      const float dx0, const float dy0,
+      const float dx1, const float dy1,
+      const float dx3, const float dy3,
+      const float dx2, const float dy2,
+      math_matrix_3x3 *mat)
+{
+   float a, b, d, e;
+   float ax  = dx0 - dx1 + dx2 - dx3;
+   float ay  = dy0 - dy1 + dy2 - dy3;
+   float c   = dx0;
+   float f   = dy0;
+   float g   = 0;
+   float h   = 0;
+
+   if (FLOAT_IS_ZERO(ax) && FLOAT_IS_ZERO(ay))
+   {
+      /* affine case */
+      a = dx1 - dx0;
+      b = dx2 - dx1;
+      d = dy1 - dy0;
+      e = dy2 - dy1;
+   }
+   else
+   {
+      float ax1 = dx1 - dx2;
+      float ax2 = dx3 - dx2;
+      float ay1 = dy1 - dy2;
+      float ay2 = dy3 - dy2;
+
+      /* determinants */
+      float gtop    =  ax  * ay2 - ax2 * ay;
+      float htop    =  ax1 * ay  - ax  * ay1;
+      float bottom  =  ax1 * ay2 - ax2 * ay1;
+
+      if (!bottom)
+         return false;
+
+      g = gtop / bottom;
+      h = htop / bottom;
+
+      a = dx1 - dx0 + g * dx1;
+      b = dx3 - dx0 + h * dx3;
+      d = dy1 - dy0 + g * dy1;
+      e = dy3 - dy0 + h * dy3;
+   }
+
+   matrix_3x3_init(*mat,
+         a, d, g,
+         b, e, h,
+         c, f, 1.f);
+
+   return true;
+}
+
+static INLINE bool matrix_3x3_quad_to_square(
+      const float sx0, const float sy0,
+      const float sx1, const float sy1,
+      const float sx2, const float sy2,
+      const float sx3, const float sy3,
+      math_matrix_3x3 *mat)
+{
+   return matrix_3x3_square_to_quad(sx0, sy0, sx1, sy1,
+         sx2, sy2, sx3, sy3,
+         mat) ? matrix_3x3_invert(mat) : false;
+}
+
+static INLINE bool matrix_3x3_quad_to_quad(
+      const float dx0, const float dy0,
+      const float dx1, const float dy1,
+      const float dx2, const float dy2,
+      const float dx3, const float dy3,
+      const float sx0, const float sy0,
+      const float sx1, const float sy1,
+      const float sx2, const float sy2,
+      const float sx3, const float sy3,
+      math_matrix_3x3 *mat)
+{
+   math_matrix_3x3 square_to_quad;
+
+   if (matrix_3x3_square_to_quad(dx0, dy0, dx1, dy1,
+            dx2, dy2, dx3, dy3,
+            &square_to_quad))
+   {
+      math_matrix_3x3 quad_to_square;
+      if (matrix_3x3_quad_to_square(sx0, sy0, sx1, sy1,
+               sx2, sy2, sx3, sy3,
+               &quad_to_square))
+      {
+         matrix_3x3_multiply(*mat, quad_to_square, square_to_quad);
+
+         return true;
+      }
+   }
+
+   return false;
+}
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/math/matrix_4x4.h b/deps/libretro-common/include/gfx/math/matrix_4x4.h
new file mode 100644 (file)
index 0000000..5b9a4cd
--- /dev/null
@@ -0,0 +1,395 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (matrix_4x4.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__
+#define __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__
+
+#include <retro_common_api.h>
+
+#include <math.h>
+#include <gfx/math/vector_3.h>
+
+/* Column-major matrix (OpenGL-style).
+ * Reimplements functionality from FF OpenGL pipeline to be able
+ * to work on GLES 2.0 and modern GL variants.
+ */
+
+#define MAT_ELEM_4X4(mat, row, column) ((mat).data[4 * (column) + (row)])
+
+RETRO_BEGIN_DECLS
+
+typedef struct math_matrix_4x4
+{
+   float data[16];
+} math_matrix_4x4;
+
+#define matrix_4x4_copy(dst, src) \
+   MAT_ELEM_4X4(dst, 0, 0) = MAT_ELEM_4X4(src, 0, 0); \
+   MAT_ELEM_4X4(dst, 0, 1) = MAT_ELEM_4X4(src, 0, 1); \
+   MAT_ELEM_4X4(dst, 0, 2) = MAT_ELEM_4X4(src, 0, 2); \
+   MAT_ELEM_4X4(dst, 0, 3) = MAT_ELEM_4X4(src, 0, 3); \
+   MAT_ELEM_4X4(dst, 1, 0) = MAT_ELEM_4X4(src, 1, 0); \
+   MAT_ELEM_4X4(dst, 1, 1) = MAT_ELEM_4X4(src, 1, 1); \
+   MAT_ELEM_4X4(dst, 1, 2) = MAT_ELEM_4X4(src, 1, 2); \
+   MAT_ELEM_4X4(dst, 1, 3) = MAT_ELEM_4X4(src, 1, 3); \
+   MAT_ELEM_4X4(dst, 2, 0) = MAT_ELEM_4X4(src, 2, 0); \
+   MAT_ELEM_4X4(dst, 2, 1) = MAT_ELEM_4X4(src, 2, 1); \
+   MAT_ELEM_4X4(dst, 2, 2) = MAT_ELEM_4X4(src, 2, 2); \
+   MAT_ELEM_4X4(dst, 2, 3) = MAT_ELEM_4X4(src, 2, 3); \
+   MAT_ELEM_4X4(dst, 3, 0) = MAT_ELEM_4X4(src, 3, 0); \
+   MAT_ELEM_4X4(dst, 3, 1) = MAT_ELEM_4X4(src, 3, 1); \
+   MAT_ELEM_4X4(dst, 3, 2) = MAT_ELEM_4X4(src, 3, 2); \
+   MAT_ELEM_4X4(dst, 3, 3) = MAT_ELEM_4X4(src, 3, 3)
+
+/*
+ * Sets mat to an identity matrix
+ */
+#define matrix_4x4_identity(mat) \
+   MAT_ELEM_4X4(mat, 0, 0)    = 1.0f; \
+   MAT_ELEM_4X4(mat, 0, 1)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 2)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 3)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 0)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 1)    = 1.0f; \
+   MAT_ELEM_4X4(mat, 1, 2)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 3)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 0)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 1)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 2)    = 1.0f; \
+   MAT_ELEM_4X4(mat, 2, 3)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 0)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2)    = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 3)    = 1.0f
+
+/*
+ * Sets out to the transposed matrix of in
+ */
+
+#define matrix_4x4_transpose(out, in) \
+   MAT_ELEM_4X4(out, 0, 0) = MAT_ELEM_4X4(in, 0, 0); \
+   MAT_ELEM_4X4(out, 1, 0) = MAT_ELEM_4X4(in, 0, 1); \
+   MAT_ELEM_4X4(out, 2, 0) = MAT_ELEM_4X4(in, 0, 2); \
+   MAT_ELEM_4X4(out, 3, 0) = MAT_ELEM_4X4(in, 0, 3); \
+   MAT_ELEM_4X4(out, 0, 1) = MAT_ELEM_4X4(in, 1, 0); \
+   MAT_ELEM_4X4(out, 1, 1) = MAT_ELEM_4X4(in, 1, 1); \
+   MAT_ELEM_4X4(out, 2, 1) = MAT_ELEM_4X4(in, 1, 2); \
+   MAT_ELEM_4X4(out, 3, 1) = MAT_ELEM_4X4(in, 1, 3); \
+   MAT_ELEM_4X4(out, 0, 2) = MAT_ELEM_4X4(in, 2, 0); \
+   MAT_ELEM_4X4(out, 1, 2) = MAT_ELEM_4X4(in, 2, 1); \
+   MAT_ELEM_4X4(out, 2, 2) = MAT_ELEM_4X4(in, 2, 2); \
+   MAT_ELEM_4X4(out, 3, 2) = MAT_ELEM_4X4(in, 2, 3); \
+   MAT_ELEM_4X4(out, 0, 3) = MAT_ELEM_4X4(in, 3, 0); \
+   MAT_ELEM_4X4(out, 1, 3) = MAT_ELEM_4X4(in, 3, 1); \
+   MAT_ELEM_4X4(out, 2, 3) = MAT_ELEM_4X4(in, 3, 2); \
+   MAT_ELEM_4X4(out, 3, 3) = MAT_ELEM_4X4(in, 3, 3)
+
+/*
+ * Builds an X-axis rotation matrix
+ */
+#define matrix_4x4_rotate_x(mat, radians) \
+{ \
+   float cosine            = cosf(radians); \
+   float sine              = sinf(radians); \
+   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \
+   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 1) = cosine; \
+   MAT_ELEM_4X4(mat, 1, 2) = -sine; \
+   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 1) = sine; \
+   MAT_ELEM_4X4(mat, 2, 2) = cosine; \
+   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
+}
+
+/*
+ * Builds a rotation matrix using the
+ * rotation around the Y-axis.
+ */
+
+#define matrix_4x4_rotate_y(mat, radians) \
+{ \
+   float cosine            = cosf(radians); \
+   float sine              = sinf(radians); \
+   MAT_ELEM_4X4(mat, 0, 0) = cosine; \
+   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 2) = -sine; \
+   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \
+   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 0) = sine; \
+   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 2) = cosine; \
+   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
+}
+
+/*
+ * Builds a rotation matrix using the
+ * rotation around the Z-axis.
+ */
+#define matrix_4x4_rotate_z(mat, radians) \
+{ \
+   float cosine            = cosf(radians); \
+   float sine              = sinf(radians); \
+   MAT_ELEM_4X4(mat, 0, 0) = cosine; \
+   MAT_ELEM_4X4(mat, 0, 1) = -sine; \
+   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 0) = sine; \
+   MAT_ELEM_4X4(mat, 1, 1) = cosine; \
+   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \
+   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \
+}
+
+/*
+ * Creates an orthographic projection matrix.
+ */
+#define matrix_4x4_ortho(mat, left, right, bottom, top, znear, zfar) \
+{ \
+   float rl                = (right) - (left); \
+   float tb                = (top)   - (bottom); \
+   float fn                = (zfar)  - (znear); \
+   MAT_ELEM_4X4(mat, 0, 0) =  2.0f / rl; \
+   MAT_ELEM_4X4(mat, 0, 1) =  0.0f; \
+   MAT_ELEM_4X4(mat, 0, 2) =  0.0f; \
+   MAT_ELEM_4X4(mat, 0, 3) = -((left) + (right))  / rl; \
+   MAT_ELEM_4X4(mat, 1, 0) =  0.0f; \
+   MAT_ELEM_4X4(mat, 1, 1) =  2.0f / tb; \
+   MAT_ELEM_4X4(mat, 1, 2) =  0.0f; \
+   MAT_ELEM_4X4(mat, 1, 3) = -((top)  + (bottom)) / tb; \
+   MAT_ELEM_4X4(mat, 2, 0) =  0.0f; \
+   MAT_ELEM_4X4(mat, 2, 1) =  0.0f; \
+   MAT_ELEM_4X4(mat, 2, 2) = -2.0f / fn; \
+   MAT_ELEM_4X4(mat, 2, 3) = -((zfar) + (znear))  / fn; \
+   MAT_ELEM_4X4(mat, 3, 0) =  0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1) =  0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2) =  0.0f; \
+   MAT_ELEM_4X4(mat, 3, 3) =  1.0f; \
+}
+
+#define matrix_4x4_lookat(out, eye, center, up) \
+{ \
+   vec3_t zaxis;   /* the "forward" vector */ \
+   vec3_t xaxis;   /* the "right"   vector */ \
+   vec3_t yaxis;   /* the "up"      vector */ \
+   vec3_copy(zaxis, center); \
+   vec3_subtract(zaxis, eye); \
+   vec3_normalize(zaxis); \
+   vec3_cross(xaxis, zaxis, up); \
+   vec3_normalize(xaxis); \
+   vec3_cross(yaxis, xaxis, zaxis); \
+   MAT_ELEM_4X4(out, 0, 0) = xaxis[0]; \
+   MAT_ELEM_4X4(out, 0, 1) = yaxis[0]; \
+   MAT_ELEM_4X4(out, 0, 2) = -zaxis[0]; \
+   MAT_ELEM_4X4(out, 0, 3) = 0.0; \
+   MAT_ELEM_4X4(out, 1, 0) = xaxis[1]; \
+   MAT_ELEM_4X4(out, 1, 1) = yaxis[1]; \
+   MAT_ELEM_4X4(out, 1, 2) = -zaxis[1]; \
+   MAT_ELEM_4X4(out, 1, 3) = 0.0f; \
+   MAT_ELEM_4X4(out, 2, 0) = xaxis[2]; \
+   MAT_ELEM_4X4(out, 2, 1) = yaxis[2]; \
+   MAT_ELEM_4X4(out, 2, 2) = -zaxis[2]; \
+   MAT_ELEM_4X4(out, 2, 3) = 0.0f; \
+   MAT_ELEM_4X4(out, 3, 0) = -(xaxis[0] * eye[0] + xaxis[1] * eye[1] + xaxis[2] * eye[2]); \
+   MAT_ELEM_4X4(out, 3, 1) = -(yaxis[0] * eye[0] + yaxis[1] * eye[1] + yaxis[2] * eye[2]); \
+   MAT_ELEM_4X4(out, 3, 2) = (zaxis[0] * eye[0] + zaxis[1] * eye[1] + zaxis[2] * eye[2]); \
+   MAT_ELEM_4X4(out, 3, 3) = 1.f; \
+}
+
+/*
+ * Multiplies a with b, stores the result in out
+ */
+
+#define matrix_4x4_multiply(out, a, b) \
+   MAT_ELEM_4X4(out, 0, 0) =  \
+      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 0) + \
+      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 0) + \
+      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 0) + \
+      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 0); \
+   MAT_ELEM_4X4(out, 0, 1) =  \
+      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 1) + \
+      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 1) + \
+      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 1) + \
+      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 1); \
+   MAT_ELEM_4X4(out, 0, 2) =  \
+      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 2) + \
+      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 2) + \
+      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 2) + \
+      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 2); \
+   MAT_ELEM_4X4(out, 0, 3) =  \
+      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 3) + \
+      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 3) + \
+      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 3) + \
+      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 3); \
+   MAT_ELEM_4X4(out, 1, 0) =  \
+      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 0) + \
+      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 0) + \
+      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 0) + \
+      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 0); \
+   MAT_ELEM_4X4(out, 1, 1) =  \
+      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 1) + \
+      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 1) + \
+      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 1) + \
+      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 1); \
+   MAT_ELEM_4X4(out, 1, 2) =  \
+      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 2) + \
+      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 2) + \
+      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 2) + \
+      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 2); \
+   MAT_ELEM_4X4(out, 1, 3) =  \
+      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 3) + \
+      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 3) + \
+      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 3) + \
+      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 3); \
+   MAT_ELEM_4X4(out, 2, 0) =  \
+      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 0) + \
+      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 0) + \
+      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 0) + \
+      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 0); \
+   MAT_ELEM_4X4(out, 2, 1) =  \
+      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 1) + \
+      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 1) + \
+      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 1) + \
+      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 1); \
+   MAT_ELEM_4X4(out, 2, 2) =  \
+      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 2) + \
+      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 2) + \
+      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 2) + \
+      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 2); \
+   MAT_ELEM_4X4(out, 2, 3) =  \
+      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 3) + \
+      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 3) + \
+      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 3) + \
+      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 3); \
+   MAT_ELEM_4X4(out, 3, 0) =  \
+      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 0) + \
+      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 0) + \
+      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 0) + \
+      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 0); \
+   MAT_ELEM_4X4(out, 3, 1) =  \
+      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 1) + \
+      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 1) + \
+      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 1) + \
+      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 1); \
+   MAT_ELEM_4X4(out, 3, 2) = \
+      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 2) + \
+      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 2) + \
+      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 2) + \
+      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 2); \
+   MAT_ELEM_4X4(out, 3, 3) =  \
+      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 3) + \
+      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 3) + \
+      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 3) + \
+      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 3)
+
+#define matrix_4x4_scale(mat, x, y, z) \
+   MAT_ELEM_4X4(mat, 0, 0) = x; \
+   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 1) = y; \
+   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 2) = z; \
+   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 3) = 1.0f
+
+/*
+ * Builds a translation matrix. All other elements in
+ * the matrix will be set to zero except for the
+ * diagonal which is set to 1.0
+ */
+
+#define matrix_4x4_translate(mat, x, y, z) \
+   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \
+   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 3) = x; \
+   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \
+   MAT_ELEM_4X4(mat, 1, 2) = 1.0f; \
+   MAT_ELEM_4X4(mat, 1, 3) = y; \
+   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \
+   MAT_ELEM_4X4(mat, 2, 3) = z; \
+   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 3) = 1.0f
+
+/*
+ * Creates a perspective projection matrix.
+ */
+
+#define  matrix_4x4_projection(mat, y_fov, aspect, znear, zfar) \
+{ \
+   float const a           = 1.f / tan((y_fov) / 2.f); \
+   float delta_z           = (zfar) - (znear); \
+   MAT_ELEM_4X4(mat, 0, 0) = a / (aspect); \
+   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 1) = a; \
+   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \
+   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 2, 2) = -(((zfar) + (znear)) / delta_z); \
+   MAT_ELEM_4X4(mat, 2, 3) = -1.f; \
+   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \
+   MAT_ELEM_4X4(mat, 3, 2) = -((2.f * (zfar) * (znear)) / delta_z); \
+   MAT_ELEM_4X4(mat, 3, 3) = 0.0f; \
+}
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/math/vector_2.h b/deps/libretro-common/include/gfx/math/vector_2.h
new file mode 100644 (file)
index 0000000..7a989fc
--- /dev/null
@@ -0,0 +1,138 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (vector_2.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__
+#define __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__
+
+#include <stdint.h>
+#include <math.h>
+
+#include <retro_common_api.h>
+#include <retro_inline.h>
+
+RETRO_BEGIN_DECLS
+
+typedef float vec2_t[2];
+
+#define vec2_dot(a, b)   ((a[0] * b[0]) + (a[1] * b[1]))
+
+#define vec2_cross(a, b) ((a[0]*b[1]) - (a[1]*b[0]))
+
+#define vec2_add(dst, src) \
+   dst[0] += src[0]; \
+   dst[1] += src[1]
+
+#define vec2_subtract(dst, src) \
+   dst[0] -= src[0]; \
+   dst[1] -= src[1]
+
+#define vec2_copy(dst, src) \
+   dst[0] = src[0]; \
+   dst[1] = src[1]
+
+static INLINE float overflow(void)
+{
+   unsigned i;
+   volatile float f = 1e10;
+
+   for (i = 0; i < 10; ++i)
+      f *= f;
+   return f;
+}
+
+static INLINE int16_t tofloat16(float f)
+{
+       union uif32
+   {
+      float f;
+      uint32_t i;
+   };
+
+   int i, s, e, m;
+   union uif32 Entry;
+   Entry.f = f;
+   i       = (int)Entry.i;
+   s       =  (i >> 16) & 0x00008000;
+   e       = ((i >> 23) & 0x000000ff) - (127 - 15);
+   m       =   i        & 0x007fffff;
+
+   if (e <= 0)
+   {
+      if (e < -10)
+         return (int16_t)(s);
+
+      m = (m | 0x00800000) >> (1 - e);
+
+      if (m & 0x00001000)
+         m += 0x00002000;
+
+      return (int16_t)(s | (m >> 13));
+   }
+
+   if (e == 0xff - (127 - 15))
+   {
+      if (m == 0)
+         return (int16_t)(s | 0x7c00);
+
+      m >>= 13;
+
+      return (int16_t)(s | 0x7c00 | m | (m == 0));
+   }
+
+   if (m &  0x00001000)
+   {
+      m += 0x00002000;
+
+      if (m & 0x00800000)
+      {
+         m =  0;
+         e += 1;
+      }
+   }
+
+   if (e > 30)
+   {
+      overflow();
+
+      return (int16_t)(s | 0x7c00);
+   }
+
+   return (int16_t)(s | (e << 10) | (m >> 13));
+}
+
+static INLINE unsigned int vec2_packHalf2x16(float vec0, float vec1)
+{
+   union
+   {
+      int16_t in[2];
+      unsigned int out;
+   } u;
+
+   u.in[0] = tofloat16(vec0);
+   u.in[1] = tofloat16(vec1);
+
+   return u.out;
+}
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/math/vector_3.h b/deps/libretro-common/include/gfx/math/vector_3.h
new file mode 100644 (file)
index 0000000..c4c9bd2
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (vector_3.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__
+#define __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__
+
+#include <stdint.h>
+#include <math.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+typedef float vec3_t[3];
+
+#define vec3_dot(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
+
+#define vec3_cross(dst, a, b)  \
+   dst[0] = a[1]*b[2] - a[2]*b[1]; \
+   dst[1] = a[2]*b[0] - a[0]*b[2]; \
+   dst[2] = a[0]*b[1] - a[1]*b[0]
+
+#define vec3_length(a) sqrtf(vec3_dot(a,a))
+
+#define vec3_add(dst, src) \
+   dst[0] += src[0]; \
+   dst[1] += src[1]; \
+   dst[2] += src[2]
+
+#define vec3_subtract(dst, src) \
+   dst[0] -= src[0]; \
+   dst[1] -= src[1]; \
+   dst[2] -= src[2]
+
+#define vec3_scale(dst, scale) \
+   dst[0] *= scale; \
+   dst[1] *= scale; \
+   dst[2] *= scale
+
+#define vec3_copy(dst, src) \
+   dst[0] = src[0]; \
+   dst[1] = src[1]; \
+   dst[2] = src[2]
+
+#define vec3_normalize(dst) vec3_scale(dst,1.0f / vec3_length(dst))
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/math/vector_4.h b/deps/libretro-common/include/gfx/math/vector_4.h
new file mode 100644 (file)
index 0000000..000f279
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (vector_4.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__
+#define __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__
+
+#include <stdint.h>
+#include <math.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+typedef float vec4_t[4];
+
+#define vec4_add(dst, src) \
+   dst[0] += src[0]; \
+   dst[1] += src[1]; \
+   dst[2] += src[2]; \
+   dst[3] += src[3]
+
+#define vec4_subtract(dst, src) \
+   dst[0] -= src[0]; \
+   dst[1] -= src[1]; \
+   dst[2] -= src[2]; \
+   dst[3] -= src[3]
+
+#define vec4_scale(dst, scale) \
+   dst[0] *= scale; \
+   dst[1] *= scale; \
+   dst[2] *= scale; \
+   dst[3] *= scale
+
+#define vec4_copy(dst, src) \
+   dst[0] = src[0]; \
+   dst[1] = src[1]; \
+   dst[2] = src[2]; \
+   dst[3] = src[3]
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/scaler/filter.h b/deps/libretro-common/include/gfx/scaler/filter.h
new file mode 100644 (file)
index 0000000..99fd210
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (filter.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_SCALER_FILTER_H__
+#define __LIBRETRO_SDK_SCALER_FILTER_H__
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#include <boolean.h>
+#include <gfx/scaler/scaler.h>
+
+bool scaler_gen_filter(struct scaler_ctx *ctx);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/scaler/pixconv.h b/deps/libretro-common/include/gfx/scaler/pixconv.h
new file mode 100644 (file)
index 0000000..60d6e46
--- /dev/null
@@ -0,0 +1,110 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (pixconv.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_SCALER_PIXCONV_H__
+#define __LIBRETRO_SDK_SCALER_PIXCONV_H__
+
+#include <clamping.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+void conv_0rgb1555_argb8888(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_0rgb1555_rgb565(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_rgb565_0rgb1555(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_rgb565_abgr8888(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_rgb565_argb8888(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_rgba4444_argb8888(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_rgba4444_rgb565(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_bgr24_argb8888(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_bgr24_rgb565(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_argb8888_0rgb1555(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_argb8888_rgba4444(void *output_, const void *input_,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_argb8888_rgb565(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_argb8888_bgr24(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_abgr8888_bgr24(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_argb8888_abgr8888(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_0rgb1555_bgr24(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_rgb565_bgr24(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_yuyv_argb8888(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+void conv_copy(void *output, const void *input,
+      int width, int height,
+      int out_stride, int in_stride);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/scaler/scaler.h b/deps/libretro-common/include/gfx/scaler/scaler.h
new file mode 100644 (file)
index 0000000..287d84d
--- /dev/null
@@ -0,0 +1,128 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (scaler.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_SCALER_H__
+#define __LIBRETRO_SDK_SCALER_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <boolean.h>
+#include <clamping.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+enum scaler_pix_fmt
+{
+   SCALER_FMT_ARGB8888 = 0,
+   SCALER_FMT_ABGR8888,
+   SCALER_FMT_0RGB1555,
+   SCALER_FMT_RGB565,
+   SCALER_FMT_BGR24,
+   SCALER_FMT_YUYV,
+   SCALER_FMT_RGBA4444
+};
+
+enum scaler_type
+{
+   SCALER_TYPE_UNKNOWN = 0,
+   SCALER_TYPE_POINT,
+   SCALER_TYPE_BILINEAR,
+   SCALER_TYPE_SINC
+};
+
+struct scaler_filter
+{
+   int16_t *filter;
+   int     *filter_pos;
+   int      filter_len;
+   int      filter_stride;
+};
+
+struct scaler_ctx
+{
+   void (*scaler_horiz)(const struct scaler_ctx*,
+         const void*, int);
+   void (*scaler_vert)(const struct scaler_ctx*,
+         void*, int);
+   void (*scaler_special)(const struct scaler_ctx*,
+         void*, const void*, int, int, int, int, int, int);
+
+   void (*in_pixconv)(void*, const void*, int, int, int, int);
+   void (*out_pixconv)(void*, const void*, int, int, int, int);
+   void (*direct_pixconv)(void*, const void*, int, int, int, int);
+   struct scaler_filter horiz, vert;   /* ptr alignment */
+
+   struct
+   {
+      uint32_t *frame;
+      int stride;
+   } input;
+
+   struct
+   {
+      uint64_t *frame;
+      int width;
+      int height;
+      int stride;
+   } scaled;
+
+   struct
+   {
+      uint32_t *frame;
+      int stride;
+   } output;
+
+   int in_width;
+   int in_height;
+   int in_stride;
+
+   int out_width;
+   int out_height;
+   int out_stride;
+
+   enum scaler_pix_fmt in_fmt;
+   enum scaler_pix_fmt out_fmt;
+   enum scaler_type scaler_type;
+
+   bool unscaled;
+};
+
+bool scaler_ctx_gen_filter(struct scaler_ctx *ctx);
+
+void scaler_ctx_gen_reset(struct scaler_ctx *ctx);
+
+/**
+ * scaler_ctx_scale:
+ * @ctx          : pointer to scaler context object.
+ * @output       : pointer to output image.
+ * @input        : pointer to input image.
+ *
+ * Scales an input image to an output image.
+ **/
+void scaler_ctx_scale(struct scaler_ctx *ctx,
+      void *output, const void *input);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/scaler/scaler_int.h b/deps/libretro-common/include/gfx/scaler/scaler_int.h
new file mode 100644 (file)
index 0000000..ad9e2fb
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (scaler_int.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_SCALER_INT_H__
+#define __LIBRETRO_SDK_SCALER_INT_H__
+
+#include <gfx/scaler/scaler.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+void scaler_argb8888_vert(const struct scaler_ctx *ctx,
+      void *output, int stride);
+
+void scaler_argb8888_horiz(const struct scaler_ctx *ctx,
+      const void *input, int stride);
+
+void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
+      void *output, const void *input,
+      int out_width, int out_height,
+      int in_width, int in_height,
+      int out_stride, int in_stride);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/gfx/video_frame.h b/deps/libretro-common/include/gfx/video_frame.h
new file mode 100644 (file)
index 0000000..05ba3f7
--- /dev/null
@@ -0,0 +1,220 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (video_frame.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_VIDEO_FRAME_H
+#define _LIBRETRO_SDK_VIDEO_FRAME_H
+
+#include <stdint.h>
+#include <retro_common_api.h>
+#include <retro_inline.h>
+
+#include <gfx/scaler/scaler.h>
+
+#include <libretro.h>
+
+RETRO_BEGIN_DECLS
+
+#define scaler_ctx_scale_direct(ctx, output, input) \
+{ \
+   if (ctx && ctx->unscaled && ctx->direct_pixconv) \
+      /* Just perform straight pixel conversion. */ \
+      ctx->direct_pixconv(output, input, \
+            ctx->out_width,  ctx->out_height, \
+            ctx->out_stride, ctx->in_stride); \
+   else \
+      scaler_ctx_scale(ctx, output, input); \
+}
+
+static INLINE void video_frame_convert_rgb16_to_rgb32(
+      struct scaler_ctx *scaler,
+      void *output,
+      const void *input,
+      int width, int height,
+      int in_pitch)
+{
+   if (width != scaler->in_width || height != scaler->in_height)
+   {
+      scaler->in_width    = width;
+      scaler->in_height   = height;
+      scaler->out_width   = width;
+      scaler->out_height  = height;
+      scaler->in_fmt      = SCALER_FMT_RGB565;
+      scaler->out_fmt     = SCALER_FMT_ARGB8888;
+      scaler->scaler_type = SCALER_TYPE_POINT;
+      scaler_ctx_gen_filter(scaler);
+   }
+
+   scaler->in_stride  = in_pitch;
+   scaler->out_stride = width * sizeof(uint32_t);
+
+   scaler_ctx_scale_direct(scaler, output, input);
+}
+
+static INLINE void video_frame_scale(
+      struct scaler_ctx *scaler,
+      void *output,
+      const void *input,
+      enum scaler_pix_fmt format,
+      unsigned scaler_width,
+      unsigned scaler_height,
+      unsigned scaler_pitch,
+      unsigned width,
+      unsigned height,
+      unsigned pitch)
+{
+   if (
+            width  != (unsigned)scaler->in_width
+         || height != (unsigned)scaler->in_height
+         || format != scaler->in_fmt
+         || pitch  != (unsigned)scaler->in_stride
+      )
+   {
+      scaler->in_fmt    = format;
+      scaler->in_width  = width;
+      scaler->in_height = height;
+      scaler->in_stride = pitch;
+
+      scaler->out_width  = scaler_width;
+      scaler->out_height = scaler_height;
+      scaler->out_stride = scaler_pitch;
+
+      scaler_ctx_gen_filter(scaler);
+   }
+
+   scaler_ctx_scale_direct(scaler, output, input);
+}
+
+static INLINE void video_frame_record_scale(
+      struct scaler_ctx *scaler,
+      void *output,
+      const void *input,
+      unsigned scaler_width,
+      unsigned scaler_height,
+      unsigned scaler_pitch,
+      unsigned width,
+      unsigned height,
+      unsigned pitch,
+      bool bilinear)
+{
+   if (
+            width  != (unsigned)scaler->in_width
+         || height != (unsigned)scaler->in_height
+      )
+   {
+      scaler->in_width    = width;
+      scaler->in_height   = height;
+      scaler->in_stride   = pitch;
+
+      scaler->scaler_type = bilinear ?
+         SCALER_TYPE_BILINEAR : SCALER_TYPE_POINT;
+
+      scaler->out_width  = scaler_width;
+      scaler->out_height = scaler_height;
+      scaler->out_stride = scaler_pitch;
+
+      scaler_ctx_gen_filter(scaler);
+   }
+
+   scaler_ctx_scale_direct(scaler, output, input);
+}
+
+static INLINE void video_frame_convert_argb8888_to_abgr8888(
+      struct scaler_ctx *scaler,
+      void *output, const void *input,
+      int width, int height, int in_pitch)
+{
+   if (width != scaler->in_width || height != scaler->in_height)
+   {
+      scaler->in_width    = width;
+      scaler->in_height   = height;
+      scaler->out_width   = width;
+      scaler->out_height  = height;
+      scaler->in_fmt      = SCALER_FMT_ARGB8888;
+      scaler->out_fmt     = SCALER_FMT_ABGR8888;
+      scaler->scaler_type = SCALER_TYPE_POINT;
+      scaler_ctx_gen_filter(scaler);
+   }
+
+   scaler->in_stride  = in_pitch;
+   scaler->out_stride = width * sizeof(uint32_t);
+
+   scaler_ctx_scale_direct(scaler, output, input);
+}
+
+static INLINE void video_frame_convert_to_bgr24(
+      struct scaler_ctx *scaler,
+      void *output, const void *input,
+      int width, int height, int in_pitch)
+{
+   scaler->in_width    = width;
+   scaler->in_height   = height;
+   scaler->out_width   = width;
+   scaler->out_height  = height;
+   scaler->out_fmt     = SCALER_FMT_BGR24;
+   scaler->scaler_type = SCALER_TYPE_POINT;
+
+   scaler_ctx_gen_filter(scaler);
+
+   scaler->in_stride   = in_pitch;
+   scaler->out_stride  = width * 3;
+
+   scaler_ctx_scale_direct(scaler, output, input);
+}
+
+static INLINE void video_frame_convert_rgba_to_bgr(
+      const void *src_data,
+      void *dst_data,
+      unsigned width)
+{
+   unsigned x;
+   uint8_t      *dst  = (uint8_t*)dst_data;
+   const uint8_t *src = (const uint8_t*)src_data;
+
+   for (x = 0; x < width; x++, dst += 3, src += 4)
+   {
+      dst[0] = src[2];
+      dst[1] = src[1];
+      dst[2] = src[0];
+   }
+}
+
+static INLINE bool video_pixel_frame_scale(
+      struct scaler_ctx *scaler,
+      void *output, const void *data,
+      unsigned width, unsigned height,
+      size_t pitch)
+{
+   scaler->in_width      = width;
+   scaler->in_height     = height;
+   scaler->out_width     = width;
+   scaler->out_height    = height;
+   scaler->in_stride     = (int)pitch;
+   scaler->out_stride    = width * sizeof(uint16_t);
+
+   scaler_ctx_scale_direct(scaler, output, data);
+
+   return true;
+}
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/glsm/glsm.h b/deps/libretro-common/include/glsm/glsm.h
new file mode 100644 (file)
index 0000000..b95e217
--- /dev/null
@@ -0,0 +1,158 @@
+/* Copyright (C) 2010-2018 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsm.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_SDK_GLSM_H
+#define LIBRETRO_SDK_GLSM_H
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+#include <libretro.h>
+#include <glsym/rglgen_headers.h>
+
+RETRO_BEGIN_DECLS
+
+#ifdef HAVE_OPENGLES2
+typedef double GLdouble;
+typedef double GLclampd;
+#endif
+
+#if defined(HAVE_OPENGLES2)
+#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER
+#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_OES
+#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT
+#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
+#elif (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
+#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER_EXT
+#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT
+#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
+#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_EXT
+#elif defined(HAVE_PSGL)
+#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER_OES
+#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_SCE
+#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES
+#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_OES
+#else
+#define RARCH_GL_RENDERBUFFER GL_RENDERBUFFER
+#define RARCH_GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8
+#define RARCH_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT
+#define RARCH_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT
+#endif
+
+#if defined(HAVE_PSGL)
+#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
+#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
+#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
+#elif (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))
+#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
+#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
+#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
+#else
+#define RARCH_GL_FRAMEBUFFER GL_FRAMEBUFFER
+#define RARCH_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE
+#define RARCH_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0
+#endif
+
+#ifndef GL_FOG
+#define GL_FOG 0x0B60
+#endif
+
+#ifndef GL_ALPHA_TEST
+#define GL_ALPHA_TEST 0x0BC0
+#endif
+
+#ifndef GL_CLIP_DISTANCE0
+#define GL_CLIP_DISTANCE0 0x3000
+#endif
+
+#define MAX_ATTRIB 8
+
+enum
+{
+   SGL_DEPTH_TEST             = 0,
+   SGL_BLEND,
+   SGL_POLYGON_OFFSET_FILL,
+   SGL_FOG,
+   SGL_CULL_FACE,
+   SGL_ALPHA_TEST,
+   SGL_SCISSOR_TEST,
+   SGL_STENCIL_TEST,
+#if !defined(HAVE_OPENGLES)
+   SGL_DEPTH_CLAMP,
+   SGL_CLIP_DISTANCE0,
+#endif
+   SGL_DITHER,
+   SGL_SAMPLE_ALPHA_TO_COVERAGE,
+   SGL_SAMPLE_COVERAGE,
+#ifndef HAVE_OPENGLES
+   SGL_COLOR_LOGIC_OP,
+#endif
+   SGL_CAP_MAX
+};
+
+enum glsm_state_ctl
+{
+   GLSM_CTL_NONE = 0,
+   GLSM_CTL_STATE_SETUP,
+   GLSM_CTL_STATE_BIND,
+   GLSM_CTL_STATE_UNBIND,
+   GLSM_CTL_STATE_CONTEXT_RESET,
+   GLSM_CTL_STATE_CONTEXT_DESTROY,
+   GLSM_CTL_STATE_CONTEXT_INIT,
+   GLSM_CTL_IS_IMM_VBO,
+   GLSM_CTL_SET_IMM_VBO,
+   GLSM_CTL_UNSET_IMM_VBO,
+   GLSM_CTL_IMM_VBO_DISABLE,
+   GLSM_CTL_IMM_VBO_DRAW,
+   GLSM_CTL_PROC_ADDRESS_GET
+};
+
+typedef bool (*glsm_imm_vbo_draw)(void *);
+typedef bool (*glsm_imm_vbo_disable)(void *);
+typedef bool (*glsm_framebuffer_lock)(void *);
+
+typedef struct glsm_ctx_proc_address
+{
+   retro_get_proc_address_t addr;
+} glsm_ctx_proc_address_t;
+
+typedef struct glsm_ctx_params
+{
+   glsm_framebuffer_lock    framebuffer_lock;
+   glsm_imm_vbo_draw        imm_vbo_draw;
+   glsm_imm_vbo_disable     imm_vbo_disable;
+   retro_hw_context_reset_t context_reset;
+   retro_hw_context_reset_t context_destroy;
+   retro_environment_t environ_cb;
+   bool stencil;
+   unsigned major;
+   unsigned minor;
+   enum retro_hw_context_type context_type;
+} glsm_ctx_params_t;
+
+GLuint glsm_get_current_framebuffer(void);
+
+bool glsm_ctl(enum glsm_state_ctl state, void *data);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/glsm/glsmsym.h b/deps/libretro-common/include/glsm/glsmsym.h
new file mode 100644 (file)
index 0000000..3c9d3bd
--- /dev/null
@@ -0,0 +1,483 @@
+/* Copyright (C) 2010-2018 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsmsym.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_SDK_GLSM_SYM_H
+#define LIBRETRO_SDK_GLSM_SYM_H
+
+#include <glsm/glsm.h>
+
+#ifdef HAVE_GLSYM_PRIVATE
+#include "glsym_private.h"
+#endif
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/* deprecated old FF-style GL symbols */
+#define glTexCoord2f                rglTexCoord2f
+
+/* more forward-compatible GL subset symbols */
+#define glDrawRangeElementsBaseVertex rglDrawRangeElementsBaseVertex
+#define glProvokingVertex           rglProvokingVertex
+#define glGetInteger64v             rglGetInteger64v
+#define glGenSamplers               rglGenSamplers
+#define glBindSampler               rglBindSampler
+#define glSamplerParameteri         rglSamplerParameteri
+#define glGetBufferSubData          rglGetBufferSubData
+#define glUniform2iv                rglUniform2iv
+#define glUniform2uiv               rglUniform2uiv
+#define glTextureView               rglTextureView
+#define glGetQueryObjectuiv         rglGetQueryObjectuiv
+#define glGenQueries                rglGenQueries
+#define glDeleteQueries             rglDeleteQueries
+#define glBeginQuery                rglBeginQuery
+#define glEndQuery                  rglEndQuery
+#define glBlitFramebuffer           rglBlitFramebuffer
+#define glVertexAttrib4f            rglVertexAttrib4f
+#define glVertexAttrib4fv           rglVertexAttrib4fv
+#define glDrawArrays                rglDrawArrays
+#define glDrawElements              rglDrawElements
+#define glCompressedTexImage2D      rglCompressedTexImage2D
+#define glBindTexture               rglBindTexture
+#define glActiveTexture             rglActiveTexture
+#define glFramebufferTexture        rglFramebufferTexture
+#define glFramebufferTexture2D      rglFramebufferTexture2D
+#define glFramebufferRenderbuffer   rglFramebufferRenderbuffer
+#define glDeleteFramebuffers        rglDeleteFramebuffers
+#define glDeleteTextures            rglDeleteTextures
+#define glDeleteBuffers             rglDeleteBuffers
+#define glRenderbufferStorage       rglRenderbufferStorage
+#define glBindRenderbuffer          rglBindRenderbuffer
+#define glDeleteRenderbuffers       rglDeleteRenderbuffers
+#define glGenRenderbuffers          rglGenRenderbuffers
+#define glGenFramebuffers           rglGenFramebuffers
+#define glGenTextures               rglGenTextures
+#define glBindFramebuffer           rglBindFramebuffer
+#define glGenerateMipmap            rglGenerateMipmap
+#define glCheckFramebufferStatus    rglCheckFramebufferStatus
+#define glBindFragDataLocation      rglBindFragDataLocation
+#define glBindAttribLocation        rglBindAttribLocation
+#define glLinkProgram               rglLinkProgram
+#define glGetProgramiv              rglGetProgramiv
+#define glGetShaderiv               rglGetShaderiv
+#define glAttachShader              rglAttachShader
+#define glDetachShader              rglDetachShader
+#define glShaderSource              rglShaderSource
+#define glCompileShader             rglCompileShader
+#define glCreateProgram             rglCreateProgram
+#define glGetShaderInfoLog          rglGetShaderInfoLog
+#define glGetProgramInfoLog         rglGetProgramInfoLog
+#define glIsProgram                 rglIsProgram
+#define glEnableVertexAttribArray   rglEnableVertexAttribArray
+#define glDisableVertexAttribArray  rglDisableVertexAttribArray
+#define glVertexAttribPointer       rglVertexAttribPointer
+#define glVertexAttribIPointer      rglVertexAttribIPointer
+#define glVertexAttribLPointer      rglVertexAttribLPointer
+#define glGetUniformLocation        rglGetUniformLocation
+#define glGenBuffers                rglGenBuffers
+#define glDisable(T)                rglDisable(S##T)
+#define glEnable(T)                 rglEnable(S##T)
+#define glIsEnabled(T)              rglIsEnabled(S##T)
+#define glUseProgram                rglUseProgram
+#define glDepthMask                 rglDepthMask
+#define glStencilMask               rglStencilMask
+#define glBufferData                rglBufferData
+#define glBufferSubData             rglBufferSubData
+#define glBindBuffer                rglBindBuffer
+#define glCreateShader              rglCreateShader
+#define glDeleteShader              rglDeleteShader
+#define glDeleteProgram             rglDeleteProgram
+#define glUniform1f                 rglUniform1f
+#define glUniform1i                 rglUniform1i
+#define glUniform2f                 rglUniform2f
+#define glUniform2i                 rglUniform2i
+#define glUniform2fv                rglUniform2fv
+#define glUniform3f                 rglUniform3f
+#define glUniform3fv                rglUniform3fv
+#define glUniform4i                 rglUniform4i
+#define glUniform4f                 rglUniform4f
+#define glUniform4fv                rglUniform4fv
+#define glUniform1ui                rglUniform1ui
+#define glUniform2ui                rglUniform2ui
+#define glUniform3ui                rglUniform3ui
+#define glUniform4ui                rglUniform4ui
+#define glGetActiveUniform          rglGetActiveUniform
+#define glBlendFunc                 rglBlendFunc
+#define glBlendFuncSeparate         rglBlendFuncSeparate
+#define glDepthFunc                 rglDepthFunc
+#define glColorMask                 rglColorMask
+#define glClearColor                rglClearColor
+#define glViewport                  rglViewport
+#define glScissor                   rglScissor
+#define glStencilFunc               rglStencilFunc
+#define glCullFace                  rglCullFace
+#define glStencilOp                 rglStencilOp
+#define glFrontFace                 rglFrontFace
+#define glDepthRange                rglDepthRange
+#define glClearDepth                rglClearDepth
+#define glPolygonOffset             rglPolygonOffset
+#define glPixelStorei               rglPixelStorei
+#define glReadBuffer                rglReadBuffer
+#define glUniformMatrix4fv          rglUniformMatrix4fv
+#define glGetAttribLocation         rglGetAttribLocation
+#define glTexStorage2D              rglTexStorage2D
+#define glDrawBuffers               rglDrawBuffers
+#define glGenVertexArrays           rglGenVertexArrays
+#define glBindVertexArray           rglBindVertexArray
+#define glBlendEquation             rglBlendEquation
+#define glBlendColor                rglBlendColor
+#define glBlendEquationSeparate     rglBlendEquationSeparate
+#define glCopyImageSubData          rglCopyImageSubData
+#define glMapBuffer                 rglMapBuffer
+#define glUnmapBuffer               rglUnmapBuffer
+#define glMapBufferRange            rglMapBufferRange
+#define glUniformBlockBinding       rglUniformBlockBinding
+#define glGetUniformBlockIndex      rglGetUniformBlockIndex
+#define glGetActiveUniformBlockiv   rglGetActiveUniformBlockiv
+#define glBindBufferBase            rglBindBufferBase
+#define glGetUniformIndices         rglGetUniformIndices
+#define glGetActiveUniformsiv       rglGetActiveUniformsiv
+#define glGetError                  rglGetError
+#define glClear                     rglClear
+#define glPolygonMode               rglPolygonMode
+#define glLineWidth                 rglLineWidth
+#define glTexImage3D                rglTexImage3D
+#define glTexImage2DMultisample     rglTexImage2DMultisample
+#define glTexStorage2DMultisample   rglTexStorage2DMultisample
+#define glMemoryBarrier             rglMemoryBarrier
+#define glBindImageTexture          rglBindImageTexture
+#define glProgramBinary             rglProgramBinary
+#define glGetProgramBinary          rglGetProgramBinary
+#define glProgramParameteri         rglProgramParameteri
+#define glTexSubImage2D             rglTexSubImage2D
+#define glDeleteVertexArrays        rglDeleteVertexArrays
+#define glRenderbufferStorageMultisample rglRenderbufferStorageMultisample
+#define glUniform1iv                rglUniform1iv
+#define glUniform1fv                rglUniform1fv
+#define glValidateProgram           rglValidateProgram
+#define glGetStringi                rglGetStringi
+#define glTexBuffer                 rglTexBuffer
+#define glClearBufferfv             rglClearBufferfv
+#define glClearBufferfi             rglClearBufferfi
+#define glWaitSync                  rglWaitSync
+#define glFenceSync                 rglFenceSync
+#define glDeleteSync                rglDeleteSync
+#define glBufferStorage             rglBufferStorage
+#define glFlushMappedBufferRange    rglFlushMappedBufferRange
+#define glClientWaitSync            rglClientWaitSync
+#define glDrawElementsBaseVertex    rglDrawElementsBaseVertex
+
+const GLubyte* rglGetStringi(GLenum name, GLuint index);
+void rglTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer);
+void rglClearBufferfv(         GLenum buffer,
+       GLint drawBuffer,
+       const GLfloat * value);
+void rglClearBufferfi(         GLenum buffer,
+       GLint drawBuffer,
+       GLfloat depth,
+       GLint stencil);
+void rglValidateProgram(GLuint program);
+void rglRenderbufferStorageMultisample(        GLenum target,
+       GLsizei samples,
+       GLenum internalformat,
+       GLsizei width,
+       GLsizei height);
+void rglUniform1iv(GLint location,  GLsizei count,  const GLint *value);
+void rglUniform1fv(GLint location,  GLsizei count,  const GLfloat *value);
+void rglProgramParameteri(     GLuint program,
+       GLenum pname,
+       GLint value);
+void rglGetProgramBinary(      GLuint program,
+       GLsizei bufsize,
+       GLsizei *length,
+       GLenum *binaryFormat,
+       void *binary);
+void rglProgramBinary(GLuint program,
+       GLenum binaryFormat,
+       const void *binary,
+       GLsizei length);
+void rglBindImageTexture(      GLuint unit,
+       GLuint texture,
+       GLint level,
+       GLboolean layered,
+       GLint layer,
+       GLenum access,
+       GLenum format);
+void rglTexStorage2DMultisample(GLenum target, GLsizei samples,
+      GLenum internalformat, GLsizei width, GLsizei height,
+      GLboolean fixedsamplelocations);
+void rglGetActiveUniformsiv(   GLuint program,
+       GLsizei uniformCount,
+       const GLuint *uniformIndices,
+       GLenum pname,
+       GLint *params);
+void rglGetUniformIndices(     GLuint program,
+       GLsizei uniformCount,
+       const GLchar **uniformNames,
+       GLuint *uniformIndices);
+void rglBindBufferBase(        GLenum target,
+       GLuint index,
+       GLuint buffer);
+void rglGetActiveUniformBlockiv(       GLuint program,
+       GLuint uniformBlockIndex,
+       GLenum pname,
+       GLint *params);
+GLuint rglGetUniformBlockIndex(        GLuint program,
+       const GLchar *uniformBlockName);
+void * rglMapBuffer(   GLenum target, GLenum access);
+void *rglMapBufferRange(       GLenum target,
+       GLintptr offset,
+       GLsizeiptr length,
+       GLbitfield access);
+GLboolean rglUnmapBuffer(      GLenum target);
+void rglBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+void rglBlendEquation(GLenum mode);
+void rglGenVertexArrays(GLsizei n, GLuint *arrays);
+void rglReadBuffer(GLenum mode);
+void rglPixelStorei(GLenum pname, GLint param);
+void rglTexCoord2f(GLfloat s, GLfloat t);
+void rglDrawElements(GLenum mode, GLsizei count, GLenum type,
+                           const GLvoid * indices);
+void rglTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
+      GLsizei width, GLsizei height);
+void rglCompressedTexImage2D(GLenum target, GLint level,
+      GLenum internalformat, GLsizei width, GLsizei height,
+      GLint border, GLsizei imageSize, const GLvoid *data);
+void glBindTexture(GLenum target, GLuint texture);
+void glActiveTexture(GLenum texture);
+void rglFramebufferTexture(GLenum target, GLenum attachment,
+       GLuint texture, GLint level);
+void rglFramebufferTexture2D(GLenum target, GLenum attachment,
+      GLenum textarget, GLuint texture, GLint level);
+void rglFramebufferRenderbuffer(GLenum target, GLenum attachment,
+      GLenum renderbuffertarget, GLuint renderbuffer);
+void rglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
+void rglRenderbufferStorage(GLenum target, GLenum internalFormat,
+      GLsizei width, GLsizei height);
+void rglDeleteTextures(GLsizei n, const GLuint *textures);
+void rglBindRenderbuffer(GLenum target, GLuint renderbuffer);
+void rglDeleteRenderbuffers(GLsizei n, GLuint *renderbuffers);
+void rglGenRenderbuffers(GLsizei n, GLuint *renderbuffers);
+void rglGenFramebuffers(GLsizei n, GLuint *ids);
+void rglGenTextures(GLsizei n, GLuint *textures);
+void rglBindFramebuffer(GLenum target, GLuint framebuffer);
+void rglGenerateMipmap(GLenum target);
+GLenum rglCheckFramebufferStatus(GLenum target);
+void rglBindFragDataLocation(GLuint program, GLuint colorNumber,
+                                   const char * name);
+void rglBindAttribLocation(GLuint program, GLuint index, const GLchar *name);
+void rglLinkProgram(GLuint program);
+void rglGetProgramiv(GLuint shader, GLenum pname, GLint *params);
+void rglGetShaderiv(GLuint shader, GLenum pname, GLint *params);
+void rglAttachShader(GLuint program, GLuint shader);
+void rglShaderSource(GLuint shader, GLsizei count,
+      const GLchar **string, const GLint *length);
+void rglCompileShader(GLuint shader);
+GLuint rglCreateProgram(void);
+void rglGetShaderInfoLog(GLuint shader, GLsizei maxLength,
+      GLsizei *length, GLchar *infoLog);
+void rglGetProgramInfoLog(GLuint shader, GLsizei maxLength,
+      GLsizei *length, GLchar *infoLog);
+GLboolean rglIsProgram(GLuint program);
+void rglEnableVertexAttribArray(GLuint index);
+void rglDisableVertexAttribArray(GLuint index);
+void rglVertexAttribPointer(GLuint name, GLint size,
+      GLenum type, GLboolean normalized, GLsizei stride,
+      const GLvoid* pointer);
+GLint rglGetUniformLocation(GLuint program, const GLchar *name);
+void rglGenBuffers(GLsizei n, GLuint *buffers);
+void rglDisable(GLenum cap);
+void rglEnable(GLenum cap);
+void rglUseProgram(GLuint program);
+void rglDepthMask(GLboolean flag);
+void rglStencilMask(GLenum mask);
+void rglBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+void rglBufferSubData(GLenum target, GLintptr offset,
+      GLsizeiptr size, const GLvoid *data);
+void rglBindBuffer(GLenum target, GLuint buffer);
+GLuint rglCreateShader(GLenum shader);
+void rglDeleteShader(GLuint shader);
+void rglUniform1f(GLint location, GLfloat v0);
+void rglUniform1i(GLint location, GLint v0);
+void rglUniform2f(GLint location, GLfloat v0, GLfloat v1);
+void rglUniform2i(GLint location, GLint v0, GLint v1);
+void rglUniform2fv(GLint location, GLsizei count, const GLfloat *value);
+void rglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+void rglUniform3fv(GLint location, GLsizei count, const GLfloat *value);
+void rglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+void rglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+void rglUniform4fv(GLint location, GLsizei count, const GLfloat *value);
+void rglBlendFunc(GLenum sfactor, GLenum dfactor);
+void rglBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha,
+      GLenum dstAlpha);
+void rglDepthFunc(GLenum func);
+void rglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+void rglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+void rglViewport(GLint x, GLint y, GLsizei width, GLsizei height);
+void rglScissor(GLint x, GLint y, GLsizei width, GLsizei height);
+GLboolean rglIsEnabled(GLenum cap);
+void rglStencilFunc(GLenum func, GLint ref, GLuint mask);
+void rglCullFace(GLenum mode);
+void rglStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
+void rglFrontFace(GLenum mode);
+void rglDepthRange(GLclampd zNear, GLclampd zFar);
+void rglClearDepth(GLdouble depth);
+void rglPolygonOffset(GLfloat factor, GLfloat units);
+void rglDrawArrays(GLenum mode, GLint first, GLsizei count);
+void rglVertexAttrib4f(GLuint name, GLfloat x, GLfloat y,
+      GLfloat z, GLfloat w);
+void rglVertexAttrib4fv(GLuint name, GLfloat* v);
+void rglDeleteProgram(GLuint program);
+void rglDeleteBuffers(GLsizei n, const GLuint *buffers);
+void rglUniform2uiv(   GLint location,
+       GLsizei count,
+       const GLuint *value);
+void rglTextureView(   GLuint texture,
+       GLenum target,
+       GLuint origtexture,
+       GLenum internalformat,
+       GLuint minlevel,
+       GLuint numlevels,
+       GLuint minlayer,
+       GLuint numlayers);
+void rglGenQueries(    GLsizei n,
+       GLuint * ids);
+void rglDeleteQueries( GLsizei n,
+       const GLuint * ids);
+void rglBeginQuery(    GLenum target,
+       GLuint id);
+void rglEndQuery(      GLenum target);
+void rglGetQueryObjectuiv(     GLuint id,
+       GLenum pname,
+       GLuint * params);
+void rglBlitFramebuffer(
+      GLint srcX0, GLint srcY0,
+      GLint srcX1, GLint srcY1,
+      GLint dstX0, GLint dstY0,
+      GLint dstX1, GLint dstY1,
+      GLbitfield mask, GLenum filter);
+void rglDetachShader(GLuint program, GLuint shader);
+void rglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose,
+      const GLfloat *value);
+GLint rglGetAttribLocation(GLuint program, const GLchar *name);
+void rglDrawBuffers(GLsizei n, const GLenum *bufs);
+void rglBindVertexArray(GLuint array);
+
+void rglGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize,
+      GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+void rglUniform1ui(GLint location, GLuint v);
+void rglUniform2ui(GLint location, GLuint v0, GLuint v1);
+void rglUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2);
+void rglUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+void rglBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
+void rglCopyImageSubData(      GLuint srcName,
+       GLenum srcTarget,
+       GLint srcLevel,
+       GLint srcX,
+       GLint srcY,
+       GLint srcZ,
+       GLuint dstName,
+       GLenum dstTarget,
+       GLint dstLevel,
+       GLint dstX,
+       GLint dstY,
+       GLint dstZ,
+       GLsizei srcWidth,
+       GLsizei srcHeight,
+       GLsizei srcDepth);
+void rglVertexAttribIPointer(
+      GLuint index,
+      GLint size,
+      GLenum type,
+      GLsizei stride,
+      const GLvoid * pointer);
+void rglVertexAttribLPointer(
+      GLuint index,
+      GLint size,
+      GLenum type,
+      GLsizei stride,
+      const GLvoid * pointer);
+void rglUniformBlockBinding(   GLuint program,
+       GLuint uniformBlockIndex,
+       GLuint uniformBlockBinding);
+GLenum rglGetError(void);
+void rglClear(GLbitfield mask);
+void rglPolygonMode(GLenum face, GLenum mode);
+void rglLineWidth(GLfloat width);
+void rglTexImage3D(    GLenum target,
+       GLint level,
+       GLint internalFormat,
+       GLsizei width,
+       GLsizei height,
+       GLsizei depth,
+       GLint border,
+       GLenum format,
+       GLenum type,
+       const GLvoid * data);
+void rglTexImage2DMultisample(         GLenum target,
+       GLsizei samples,
+       GLenum internalformat,
+       GLsizei width,
+       GLsizei height,
+       GLboolean fixedsamplelocations);
+void rglMemoryBarrier(         GLbitfield barriers);
+void rglTexSubImage2D(         GLenum target,
+       GLint level,
+       GLint xoffset,
+       GLint yoffset,
+       GLsizei width,
+       GLsizei height,
+       GLenum format,
+       GLenum type,
+       const GLvoid * pixels);
+void rglDeleteVertexArrays(GLsizei n, const GLuint *arrays);
+void *rglFenceSync(GLenum condition, GLbitfield flags);
+void rglDeleteSync(void *sync);
+void rglWaitSync(void *sync, GLbitfield flags, uint64_t timeout);
+void rglBufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, GLbitfield flags);
+void rglFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length);
+GLenum rglClientWaitSync(void *sync, GLbitfield flags, uint64_t timeout);
+void rglDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
+                              GLvoid *indices, GLint basevertex);
+void rglGetBufferSubData(      GLenum target,
+       GLintptr offset,
+       GLsizeiptr size,
+       GLvoid * data);
+void rglSamplerParameteri(     GLuint sampler,
+       GLenum pname,
+       GLint param);
+void rglBindSampler(   GLuint unit,
+       GLuint sampler);
+void rglGenSamplers(   GLsizei n,
+       GLuint *samplers);
+void rglGetInteger64v( GLenum pname,
+       int64_t * data);
+void rglUniform2iv(    GLint location,
+       GLsizei count,
+       const GLint *value);
+void rglProvokingVertex(       GLenum provokeMode);
+void rglDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/glsym/glsym.h b/deps/libretro-common/include/glsym/glsym.h
new file mode 100644 (file)
index 0000000..b004036
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsym).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_GLSYM_H__
+#define __LIBRETRO_SDK_GLSYM_H__
+
+#include "rglgen.h"
+
+#ifndef HAVE_PSGL
+#if defined(HAVE_OPENGLES2)
+#include "glsym_es2.h"
+#elif defined(HAVE_OPENGLES3)
+#include "glsym_es3.h"
+#else
+#ifdef HAVE_LIBNX
+#include "switch/nx_glsym.h"
+#endif
+#include "glsym_gl.h"
+#endif
+#endif
+
+#ifdef HAVE_GLSYM_PRIVATE
+#include "glsym_private.h"
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/glsym/glsym_es2.h b/deps/libretro-common/include/glsym/glsym_es2.h
new file mode 100644 (file)
index 0000000..666d84d
--- /dev/null
@@ -0,0 +1,639 @@
+#ifndef RGLGEN_DECL_H__
+#define RGLGEN_DECL_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef GL_APIENTRY
+typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+#else
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+#endif
+#ifndef GL_OES_EGL_image
+typedef void *GLeglImageOES;
+#endif
+#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)
+typedef GLint GLfixed;
+#endif
+
+typedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);
+typedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);
+typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAOESPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);
+typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+typedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);
+typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);
+typedef void (GL_APIENTRYP RGLSYMGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+typedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);
+typedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);
+typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);
+typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);
+typedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
+typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);
+typedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+typedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
+typedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
+typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+typedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
+typedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
+typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+typedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
+typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);
+typedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);
+typedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
+typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+typedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);
+
+#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR
+#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR
+#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR
+#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR
+#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR
+#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR
+#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR
+#define glObjectLabelKHR __rglgen_glObjectLabelKHR
+#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR
+#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR
+#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR
+#define glGetPointervKHR __rglgen_glGetPointervKHR
+#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR
+#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR
+#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR
+#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR
+#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR
+#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES
+#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES
+#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES
+#define glEnableiOES __rglgen_glEnableiOES
+#define glDisableiOES __rglgen_glDisableiOES
+#define glBlendEquationiOES __rglgen_glBlendEquationiOES
+#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES
+#define glBlendFunciOES __rglgen_glBlendFunciOES
+#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES
+#define glColorMaskiOES __rglgen_glColorMaskiOES
+#define glIsEnablediOES __rglgen_glIsEnablediOES
+#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES
+#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES
+#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES
+#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES
+#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES
+#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES
+#define glProgramBinaryOES __rglgen_glProgramBinaryOES
+#define glMapBufferOES __rglgen_glMapBufferOES
+#define glUnmapBufferOES __rglgen_glUnmapBufferOES
+#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES
+#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES
+#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES
+#define glPatchParameteriOES __rglgen_glPatchParameteriOES
+#define glTexImage3DOES __rglgen_glTexImage3DOES
+#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES
+#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES
+#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES
+#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES
+#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES
+#define glTexParameterIivOES __rglgen_glTexParameterIivOES
+#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES
+#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES
+#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES
+#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES
+#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES
+#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES
+#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES
+#define glTexBufferOES __rglgen_glTexBufferOES
+#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES
+#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES
+#define glTextureViewOES __rglgen_glTextureViewOES
+#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES
+#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES
+#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES
+#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES
+#define glViewportArrayvOES __rglgen_glViewportArrayvOES
+#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES
+#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES
+#define glScissorArrayvOES __rglgen_glScissorArrayvOES
+#define glScissorIndexedOES __rglgen_glScissorIndexedOES
+#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES
+#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES
+#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES
+#define glGetFloati_vOES __rglgen_glGetFloati_vOES
+#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT
+#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT
+#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT
+#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT
+#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT
+#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT
+#define glBufferStorageEXT __rglgen_glBufferStorageEXT
+#define glClearTexImageEXT __rglgen_glClearTexImageEXT
+#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT
+#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT
+#define glLabelObjectEXT __rglgen_glLabelObjectEXT
+#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT
+#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT
+#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT
+#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT
+#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT
+#define glGenQueriesEXT __rglgen_glGenQueriesEXT
+#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT
+#define glIsQueryEXT __rglgen_glIsQueryEXT
+#define glBeginQueryEXT __rglgen_glBeginQueryEXT
+#define glEndQueryEXT __rglgen_glEndQueryEXT
+#define glQueryCounterEXT __rglgen_glQueryCounterEXT
+#define glGetQueryivEXT __rglgen_glGetQueryivEXT
+#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT
+#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT
+#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT
+#define glEnableiEXT __rglgen_glEnableiEXT
+#define glDisableiEXT __rglgen_glDisableiEXT
+#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT
+#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT
+#define glBlendFunciEXT __rglgen_glBlendFunciEXT
+#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT
+#define glColorMaskiEXT __rglgen_glColorMaskiEXT
+#define glIsEnablediEXT __rglgen_glIsEnablediEXT
+#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT
+#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT
+#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT
+#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT
+#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT
+#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT
+#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT
+#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT
+#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT
+#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT
+#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT
+#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT
+#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT
+#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT
+#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT
+#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT
+#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT
+#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT
+#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT
+#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT
+#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT
+#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT
+#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT
+#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT
+#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT
+#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT
+#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT
+#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT
+#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT
+#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT
+#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT
+#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT
+#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT
+#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT
+#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT
+#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT
+#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT
+#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT
+#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT
+#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT
+#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT
+#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT
+#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT
+#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT
+#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT
+#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT
+#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT
+#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT
+#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT
+#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT
+#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT
+#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT
+#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT
+#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT
+#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT
+#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT
+#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT
+#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT
+#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT
+#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT
+#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT
+#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT
+#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT
+#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT
+#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT
+#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT
+#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT
+#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT
+#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT
+#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT
+#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT
+#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT
+#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT
+#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT
+#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT
+#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT
+#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT
+#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT
+#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT
+#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT
+#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT
+#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT
+#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT
+#define glTexBufferEXT __rglgen_glTexBufferEXT
+#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT
+#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT
+#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT
+#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT
+#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT
+#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT
+#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT
+#define glTextureViewEXT __rglgen_glTextureViewEXT
+#define glesEXT __rglgen_glesEXT
+#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR
+#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR
+
+extern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
+extern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
+extern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
+extern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
+extern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
+extern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
+extern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
+extern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
+extern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
+extern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
+extern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
+extern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
+extern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
+extern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
+extern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
+extern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
+extern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
+extern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
+extern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
+extern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
+extern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
+extern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
+extern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
+extern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
+extern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
+extern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
+extern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
+extern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
+extern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
+extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
+extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
+extern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
+extern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
+extern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
+extern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
+extern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
+extern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
+extern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
+extern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
+extern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
+extern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
+extern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
+extern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
+extern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
+extern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
+extern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
+extern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
+extern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
+extern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
+extern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
+extern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
+extern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
+extern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
+extern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
+extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
+extern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
+extern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
+extern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
+extern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
+extern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
+extern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
+extern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
+extern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
+extern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
+extern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
+extern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
+extern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
+extern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
+extern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
+extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
+extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
+extern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
+extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
+extern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
+extern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
+extern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
+extern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
+extern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
+extern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
+extern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
+extern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
+extern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
+extern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
+extern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
+extern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
+extern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
+extern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
+extern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
+extern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
+extern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
+extern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
+extern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
+extern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
+extern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
+extern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
+extern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
+extern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
+extern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
+extern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
+extern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
+extern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
+extern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
+extern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
+extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
+extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
+extern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
+extern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
+extern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
+extern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
+extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
+extern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
+extern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
+extern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
+extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
+extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
+extern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
+extern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
+extern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
+extern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
+extern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
+extern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
+extern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
+extern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
+extern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
+extern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
+extern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
+extern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
+extern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
+extern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
+extern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
+extern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
+extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
+extern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
+extern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
+extern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
+extern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
+extern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
+extern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
+extern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
+extern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
+extern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
+extern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
+extern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
+extern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
+extern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
+extern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
+extern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
+extern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
+extern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
+extern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
+extern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
+extern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
+extern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
+extern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
+extern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
+extern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
+extern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
+extern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
+extern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
+extern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
+extern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
+extern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
+extern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
+extern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
+extern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
+extern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
+extern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
+extern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
+extern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
+extern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
+extern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
+extern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
+extern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
+extern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
+extern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
+extern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
+extern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
+
+struct rglgen_sym_map { const char *sym; void *ptr; };
+extern const struct rglgen_sym_map rglgen_symbol_map[];
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/deps/libretro-common/include/glsym/glsym_es3.h b/deps/libretro-common/include/glsym/glsym_es3.h
new file mode 100644 (file)
index 0000000..89ffc72
--- /dev/null
@@ -0,0 +1,653 @@
+#ifndef RGLGEN_DECL_H__
+#define RGLGEN_DECL_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef GL_APIENTRY
+typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+#else
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+#endif
+#ifndef GL_OES_EGL_image
+typedef void *GLeglImageOES;
+#endif
+#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)
+typedef GLint GLfixed;
+#endif
+#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)
+typedef long long int GLint64;
+typedef unsigned long long int GLuint64;
+typedef unsigned long long int GLuint64EXT;
+typedef struct __GLsync *GLsync;
+#endif
+#ifndef GL_APIENTRYP
+#define GL_APIENTRYP GL_APIENTRY*
+#endif
+typedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);
+typedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);
+typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAOESPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);
+typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+typedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);
+typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);
+typedef void (GL_APIENTRYP RGLSYMGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+typedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+typedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);
+typedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);
+typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);
+typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);
+typedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
+typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+typedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);
+typedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+typedef void (GL_APIENTRYP RGLSYMGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+typedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
+typedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);
+typedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+typedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
+typedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
+typedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
+typedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+typedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
+typedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);
+typedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);
+typedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
+typedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+typedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+typedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);
+
+#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR
+#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR
+#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR
+#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR
+#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR
+#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR
+#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR
+#define glObjectLabelKHR __rglgen_glObjectLabelKHR
+#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR
+#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR
+#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR
+#define glGetPointervKHR __rglgen_glGetPointervKHR
+#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR
+#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR
+#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR
+#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR
+#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR
+#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES
+#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES
+#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES
+#define glEnableiOES __rglgen_glEnableiOES
+#define glDisableiOES __rglgen_glDisableiOES
+#define glBlendEquationiOES __rglgen_glBlendEquationiOES
+#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES
+#define glBlendFunciOES __rglgen_glBlendFunciOES
+#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES
+#define glColorMaskiOES __rglgen_glColorMaskiOES
+#define glIsEnablediOES __rglgen_glIsEnablediOES
+#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES
+#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES
+#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES
+#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES
+#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES
+#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES
+#define glProgramBinaryOES __rglgen_glProgramBinaryOES
+#define glMapBufferOES __rglgen_glMapBufferOES
+#define glUnmapBufferOES __rglgen_glUnmapBufferOES
+#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES
+#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES
+#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES
+#define glPatchParameteriOES __rglgen_glPatchParameteriOES
+#define glTexImage3DOES __rglgen_glTexImage3DOES
+#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES
+#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES
+#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES
+#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES
+#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES
+#define glTexParameterIivOES __rglgen_glTexParameterIivOES
+#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES
+#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES
+#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES
+#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES
+#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES
+#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES
+#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES
+#define glTexBufferOES __rglgen_glTexBufferOES
+#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES
+#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES
+#define glTextureViewOES __rglgen_glTextureViewOES
+#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES
+#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES
+#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES
+#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES
+#define glViewportArrayvOES __rglgen_glViewportArrayvOES
+#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES
+#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES
+#define glScissorArrayvOES __rglgen_glScissorArrayvOES
+#define glScissorIndexedOES __rglgen_glScissorIndexedOES
+#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES
+#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES
+#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES
+#define glGetFloati_vOES __rglgen_glGetFloati_vOES
+#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT
+#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT
+#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT
+#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT
+#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT
+#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT
+#define glBufferStorageEXT __rglgen_glBufferStorageEXT
+#define glClearTexImageEXT __rglgen_glClearTexImageEXT
+#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT
+#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT
+#define glLabelObjectEXT __rglgen_glLabelObjectEXT
+#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT
+#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT
+#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT
+#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT
+#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT
+#define glGenQueriesEXT __rglgen_glGenQueriesEXT
+#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT
+#define glIsQueryEXT __rglgen_glIsQueryEXT
+#define glBeginQueryEXT __rglgen_glBeginQueryEXT
+#define glEndQueryEXT __rglgen_glEndQueryEXT
+#define glQueryCounterEXT __rglgen_glQueryCounterEXT
+#define glGetQueryivEXT __rglgen_glGetQueryivEXT
+#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT
+#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT
+#define glGetQueryObjecti64vEXT __rglgen_glGetQueryObjecti64vEXT
+#define glGetQueryObjectui64vEXT __rglgen_glGetQueryObjectui64vEXT
+#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT
+#define glEnableiEXT __rglgen_glEnableiEXT
+#define glDisableiEXT __rglgen_glDisableiEXT
+#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT
+#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT
+#define glBlendFunciEXT __rglgen_glBlendFunciEXT
+#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT
+#define glColorMaskiEXT __rglgen_glColorMaskiEXT
+#define glIsEnablediEXT __rglgen_glIsEnablediEXT
+#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT
+#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT
+#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT
+#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT
+#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT
+#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT
+#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT
+#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT
+#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT
+#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT
+#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT
+#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT
+#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT
+#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT
+#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT
+#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT
+#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT
+#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT
+#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT
+#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT
+#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT
+#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT
+#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT
+#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT
+#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT
+#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT
+#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT
+#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT
+#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT
+#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT
+#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT
+#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT
+#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT
+#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT
+#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT
+#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT
+#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT
+#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT
+#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT
+#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT
+#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT
+#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT
+#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT
+#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT
+#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT
+#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT
+#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT
+#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT
+#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT
+#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT
+#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT
+#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT
+#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT
+#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT
+#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT
+#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT
+#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT
+#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT
+#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT
+#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT
+#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT
+#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT
+#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT
+#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT
+#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT
+#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT
+#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT
+#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT
+#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT
+#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT
+#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT
+#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT
+#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT
+#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT
+#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT
+#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT
+#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT
+#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT
+#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT
+#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT
+#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT
+#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT
+#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT
+#define glTexBufferEXT __rglgen_glTexBufferEXT
+#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT
+#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT
+#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT
+#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT
+#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT
+#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT
+#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT
+#define glTextureViewEXT __rglgen_glTextureViewEXT
+#define glesEXT __rglgen_glesEXT
+#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR
+#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR
+
+extern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
+extern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
+extern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
+extern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
+extern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
+extern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
+extern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
+extern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
+extern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
+extern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
+extern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
+extern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
+extern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
+extern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
+extern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
+extern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
+extern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
+extern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
+extern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
+extern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
+extern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
+extern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
+extern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
+extern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
+extern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
+extern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
+extern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
+extern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
+extern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
+extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
+extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
+extern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
+extern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
+extern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
+extern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
+extern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
+extern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
+extern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
+extern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
+extern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
+extern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
+extern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
+extern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
+extern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
+extern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
+extern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
+extern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
+extern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
+extern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
+extern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
+extern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
+extern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
+extern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
+extern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
+extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
+extern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
+extern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
+extern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
+extern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
+extern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
+extern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
+extern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
+extern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
+extern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
+extern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
+extern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
+extern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
+extern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
+extern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
+extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
+extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
+extern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
+extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
+extern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
+extern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
+extern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
+extern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
+extern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
+extern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
+extern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
+extern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
+extern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
+extern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
+extern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
+extern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
+extern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
+extern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
+extern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
+extern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
+extern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
+extern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
+extern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
+extern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
+extern RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;
+extern RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;
+extern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
+extern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
+extern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
+extern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
+extern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
+extern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
+extern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
+extern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
+extern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
+extern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
+extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
+extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
+extern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
+extern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
+extern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
+extern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
+extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
+extern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
+extern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
+extern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
+extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
+extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
+extern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
+extern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
+extern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
+extern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
+extern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
+extern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
+extern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
+extern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
+extern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
+extern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
+extern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
+extern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
+extern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
+extern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
+extern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
+extern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
+extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
+extern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
+extern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
+extern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
+extern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
+extern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
+extern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
+extern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
+extern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
+extern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
+extern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
+extern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
+extern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
+extern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
+extern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
+extern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
+extern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
+extern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
+extern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
+extern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
+extern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
+extern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
+extern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
+extern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
+extern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
+extern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
+extern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
+extern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
+extern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
+extern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
+extern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
+extern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
+extern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
+extern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
+extern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
+extern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
+extern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
+extern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
+extern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
+extern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
+extern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
+extern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
+extern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
+extern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
+extern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
+extern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
+extern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
+extern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
+
+struct rglgen_sym_map { const char *sym; void *ptr; };
+extern const struct rglgen_sym_map rglgen_symbol_map[];
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/deps/libretro-common/include/glsym/glsym_gl.h b/deps/libretro-common/include/glsym/glsym_gl.h
new file mode 100644 (file)
index 0000000..a4e76a2
--- /dev/null
@@ -0,0 +1,3140 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsym).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 RGLGEN_DECL_H__
+#define RGLGEN_DECL_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef GL_APIENTRY
+typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+#else
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);
+#endif
+#ifndef GL_OES_EGL_image
+typedef void *GLeglImageOES;
+#endif
+#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)
+typedef GLint GLfixed;
+#endif
+#if defined(__MACH__) && !defined(OS_TARGET_IPHONE) && !defined(MAC_OS_X_VERSION_10_7)
+typedef long long int GLint64;
+typedef unsigned long long int GLuint64;
+typedef unsigned long long int GLuint64EXT;
+typedef struct __GLsync *GLsync;
+#endif
+typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);
+typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);
+typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);
+typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
+typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);
+typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
+typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);
+typedef void (APIENTRYP RGLSYMGLFOGCOORDFPROC) (GLfloat coord);
+typedef void (APIENTRYP RGLSYMGLFOGCOORDFVPROC) (const GLfloat *coord);
+typedef void (APIENTRYP RGLSYMGLFOGCOORDDPROC) (GLdouble coord);
+typedef void (APIENTRYP RGLSYMGLFOGCOORDDVPROC) (const GLdouble *coord);
+typedef void (APIENTRYP RGLSYMGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IVPROC) (const GLint *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IPROC) (GLint x, GLint y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVPROC) (const GLint *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVPROC) (const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVPROC) (const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVPROC) (const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVPROC) (const GLint *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVPROC) (const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) (GLenum mode);
+typedef void (APIENTRYP RGLSYMGLGENQUERIESPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP RGLSYMGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP RGLSYMGLISQUERYPROC) (GLuint id);
+typedef void (APIENTRYP RGLSYMGLBEGINQUERYPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP RGLSYMGLENDQUERYPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP RGLSYMGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP RGLSYMGLISBUFFERPROC) (GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data);
+typedef void *(APIENTRYP RGLSYMGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params);
+typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP RGLSYMGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP RGLSYMGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (APIENTRYP RGLSYMGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask);
+typedef void (APIENTRYP RGLSYMGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
+typedef void (APIENTRYP RGLSYMGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRYP RGLSYMGLCREATEPROGRAMPROC) (void);
+typedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP RGLSYMGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRYP RGLSYMGLDETACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);
+typedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP RGLSYMGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);
+typedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
+typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPROC) (GLuint program);
+typedef GLboolean (APIENTRYP RGLSYMGLISSHADERPROC) (GLuint shader);
+typedef void (APIENTRYP RGLSYMGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP RGLSYMGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
+typedef void (APIENTRYP RGLSYMGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef void (APIENTRYP RGLSYMGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
+typedef void (APIENTRYP RGLSYMGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
+typedef void (APIENTRYP RGLSYMGLENABLEIPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP RGLSYMGLDISABLEIPROC) (GLenum target, GLuint index);
+typedef GLboolean (APIENTRYP RGLSYMGLISENABLEDIPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP RGLSYMGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);
+typedef void (APIENTRYP RGLSYMGLENDTRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP RGLSYMGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP RGLSYMGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);
+typedef void (APIENTRYP RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);
+typedef void (APIENTRYP RGLSYMGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);
+typedef void (APIENTRYP RGLSYMGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);
+typedef void (APIENTRYP RGLSYMGLENDCONDITIONALRENDERPROC) (void);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name);
+typedef GLint (APIENTRYP RGLSYMGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1UIPROC) (GLint location, GLuint v0);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params);
+typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+typedef const GLubyte *(APIENTRYP RGLSYMGLGETSTRINGIPROC) (GLenum name, GLuint index);
+typedef GLboolean (APIENTRYP RGLSYMGLISRENDERBUFFERPROC) (GLuint renderbuffer);
+typedef void (APIENTRYP RGLSYMGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);
+typedef void (APIENTRYP RGLSYMGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers);
+typedef void (APIENTRYP RGLSYMGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);
+typedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef GLboolean (APIENTRYP RGLSYMGLISFRAMEBUFFERPROC) (GLuint framebuffer);
+typedef void (APIENTRYP RGLSYMGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
+typedef void (APIENTRYP RGLSYMGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers);
+typedef void (APIENTRYP RGLSYMGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);
+typedef GLenum (APIENTRYP RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGENERATEMIPMAPPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+typedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void *(APIENTRYP RGLSYMGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP RGLSYMGLBINDVERTEXARRAYPROC) (GLuint array);
+typedef void (APIENTRYP RGLSYMGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
+typedef void (APIENTRYP RGLSYMGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (APIENTRYP RGLSYMGLISVERTEXARRAYPROC) (GLuint array);
+typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);
+typedef void (APIENTRYP RGLSYMGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLPRIMITIVERESTARTINDEXPROC) (GLuint index);
+typedef void (APIENTRYP RGLSYMGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
+typedef GLuint (APIENTRYP RGLSYMGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
+typedef void (APIENTRYP RGLSYMGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);
+typedef void (APIENTRYP RGLSYMGLPROVOKINGVERTEXPROC) (GLenum mode);
+typedef GLsync (APIENTRYP RGLSYMGLFENCESYNCPROC) (GLenum condition, GLbitfield flags);
+typedef GLboolean (APIENTRYP RGLSYMGLISSYNCPROC) (GLsync sync);
+typedef void (APIENTRYP RGLSYMGLDELETESYNCPROC) (GLsync sync);
+typedef GLenum (APIENTRYP RGLSYMGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (APIENTRYP RGLSYMGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (APIENTRYP RGLSYMGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data);
+typedef void (APIENTRYP RGLSYMGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+typedef void (APIENTRYP RGLSYMGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
+typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP RGLSYMGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val);
+typedef void (APIENTRYP RGLSYMGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask);
+typedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);
+typedef GLint (APIENTRYP RGLSYMGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
+typedef void (APIENTRYP RGLSYMGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers);
+typedef GLboolean (APIENTRYP RGLSYMGLISSAMPLERPROC) (GLuint sampler);
+typedef void (APIENTRYP RGLSYMGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
+typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);
+typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);
+typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);
+typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param);
+typedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param);
+typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLQUERYCOUNTERPROC) (GLuint id, GLenum target);
+typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params);
+typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLVERTEXP2UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP RGLSYMGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLVERTEXP3UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP RGLSYMGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLVERTEXP4UIPROC) (GLenum type, GLuint value);
+typedef void (APIENTRYP RGLSYMGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLNORMALP3UIPROC) (GLenum type, GLuint coords);
+typedef void (APIENTRYP RGLSYMGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords);
+typedef void (APIENTRYP RGLSYMGLCOLORP3UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP RGLSYMGLCOLORP3UIVPROC) (GLenum type, const GLuint *color);
+typedef void (APIENTRYP RGLSYMGLCOLORP4UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP RGLSYMGLCOLORP4UIVPROC) (GLenum type, const GLuint *color);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color);
+typedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color);
+typedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGPROC) (GLfloat value);
+typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP RGLSYMGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1DPROC) (GLint location, GLdouble x);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params);
+typedef GLint (APIENTRYP RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name);
+typedef GLuint (APIENTRYP RGLSYMGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);
+typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP RGLSYMGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values);
+typedef void (APIENTRYP RGLSYMGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
+typedef void (APIENTRYP RGLSYMGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values);
+typedef void (APIENTRYP RGLSYMGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP RGLSYMGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids);
+typedef void (APIENTRYP RGLSYMGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);
+typedef GLboolean (APIENTRYP RGLSYMGLISTRANSFORMFEEDBACKPROC) (GLuint id);
+typedef void (APIENTRYP RGLSYMGLPAUSETRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP RGLSYMGLRESUMETRANSFORMFEEDBACKPROC) (void);
+typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);
+typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream);
+typedef void (APIENTRYP RGLSYMGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id);
+typedef void (APIENTRYP RGLSYMGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index);
+typedef void (APIENTRYP RGLSYMGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLRELEASESHADERCOMPILERPROC) (void);
+typedef void (APIENTRYP RGLSYMGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);
+typedef void (APIENTRYP RGLSYMGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);
+typedef void (APIENTRYP RGLSYMGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f);
+typedef void (APIENTRYP RGLSYMGLCLEARDEPTHFPROC) (GLfloat d);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);
+typedef void (APIENTRYP RGLSYMGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
+typedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (APIENTRYP RGLSYMGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (APIENTRYP RGLSYMGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings);
+typedef void (APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (APIENTRYP RGLSYMGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);
+typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);
+typedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f);
+typedef void (APIENTRYP RGLSYMGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
+typedef void (APIENTRYP RGLSYMGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
+typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);
+typedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+typedef void (APIENTRYP RGLSYMGLMEMORYBARRIERPROC) (GLbitfield barriers);
+typedef void (APIENTRYP RGLSYMGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount);
+typedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);
+typedef void (APIENTRYP RGLSYMGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP RGLSYMGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
+typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect);
+typedef void (APIENTRYP RGLSYMGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);
+typedef void (APIENTRYP RGLSYMGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (APIENTRYP RGLSYMGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level);
+typedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
+typedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERDATAPROC) (GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+typedef void (APIENTRYP RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params);
+typedef GLuint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);
+typedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);
+typedef void (APIENTRYP RGLSYMGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (APIENTRYP RGLSYMGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);
+typedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
+typedef void (APIENTRYP RGLSYMGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
+typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKPROC) (RGLGENGLDEBUGPROC callback, const void *userParam);
+typedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (APIENTRYP RGLSYMGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (APIENTRYP RGLSYMGLPOPDEBUGGROUPPROC) (void);
+typedef void (APIENTRYP RGLSYMGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP RGLSYMGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (APIENTRYP RGLSYMGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (APIENTRYP RGLSYMGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (APIENTRYP RGLSYMGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (APIENTRYP RGLSYMGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP RGLSYMGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
+typedef void (APIENTRYP RGLSYMGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);
+typedef void (APIENTRYP RGLSYMGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);
+typedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
+typedef void (APIENTRYP RGLSYMGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);
+typedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
+typedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);
+typedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTUREHANDLEARBPROC) (GLuint texture);
+typedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler);
+typedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle);
+typedef GLuint64 (APIENTRYP RGLSYMGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
+typedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access);
+typedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value);
+typedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
+typedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef GLboolean (APIENTRYP RGLSYMGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
+#ifdef __APPLE__
+       struct _cl_context;
+       struct _cl_event;
+#endif
+typedef GLsync (APIENTRYP RGLSYMGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);
+typedef void (APIENTRYP RGLSYMGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);
+typedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);
+typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKARBPROC) (RGLGENGLDEBUGPROCARB callback, const void *userParam);
+typedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (APIENTRYP RGLSYMGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);
+typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode);
+typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (APIENTRYP RGLSYMGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst);
+typedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+typedef void (APIENTRYP RGLSYMGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);
+typedef void (APIENTRYP RGLSYMGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);
+typedef void (APIENTRYP RGLSYMGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);
+typedef void (APIENTRYP RGLSYMGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);
+typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);
+typedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMARBPROC) (GLuint program);
+typedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);
+typedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
+typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);
+typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
+typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);
+typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+typedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
+typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
+typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP RGLSYMGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
+typedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor);
+typedef void (APIENTRYP RGLSYMGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
+typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);
+typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);
+typedef void (APIENTRYP RGLSYMGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);
+typedef void (APIENTRYP RGLSYMGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert);
+typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);
+typedef void (APIENTRYP RGLSYMGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (APIENTRYP RGLSYMGLISQUERYARBPROC) (GLuint id);
+typedef void (APIENTRYP RGLSYMGLBEGINQUERYARBPROC) (GLenum target, GLuint id);
+typedef void (APIENTRYP RGLSYMGLENDQUERYARBPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);
+typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);
+typedef GLenum (APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC) (void);
+typedef void (APIENTRYP RGLSYMGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);
+typedef void (APIENTRYP RGLSYMGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (APIENTRYP RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img);
+typedef void (APIENTRYP RGLSYMGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+typedef void (APIENTRYP RGLSYMGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);
+typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values);
+typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values);
+typedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values);
+typedef void (APIENTRYP RGLSYMGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern);
+typedef void (APIENTRYP RGLSYMGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);
+typedef void (APIENTRYP RGLSYMGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);
+typedef void (APIENTRYP RGLSYMGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);
+typedef void (APIENTRYP RGLSYMGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+typedef void (APIENTRYP RGLSYMGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);
+typedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGARBPROC) (GLfloat value);
+typedef void (APIENTRYP RGLSYMGLDELETEOBJECTARBPROC) (GLhandleARB obj);
+typedef GLhandleARB (APIENTRYP RGLSYMGLGETHANDLEARBPROC) (GLenum pname);
+typedef void (APIENTRYP RGLSYMGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);
+typedef GLhandleARB (APIENTRYP RGLSYMGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);
+typedef void (APIENTRYP RGLSYMGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);
+typedef void (APIENTRYP RGLSYMGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);
+typedef GLhandleARB (APIENTRYP RGLSYMGLCREATEPROGRAMOBJECTARBPROC) (void);
+typedef void (APIENTRYP RGLSYMGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);
+typedef void (APIENTRYP RGLSYMGLLINKPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP RGLSYMGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1IARBPROC) (GLint location, GLint v0);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);
+typedef void (APIENTRYP RGLSYMGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);
+typedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);
+typedef void (APIENTRYP RGLSYMGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);
+typedef void (APIENTRYP RGLSYMGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);
+typedef GLboolean (APIENTRYP RGLSYMGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);
+typedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);
+typedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);
+typedef void (APIENTRYP RGLSYMGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img);
+typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);
+typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);
+typedef void (APIENTRYP RGLSYMGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);
+typedef void (APIENTRYP RGLSYMGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLVERTEXBLENDARBPROC) (GLint count);
+typedef void (APIENTRYP RGLSYMGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRYP RGLSYMGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
+typedef GLboolean (APIENTRYP RGLSYMGLISBUFFERARBPROC) (GLuint buffer);
+typedef void (APIENTRYP RGLSYMGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
+typedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
+typedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
+typedef void *(APIENTRYP RGLSYMGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERARBPROC) (GLenum target);
+typedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);
+typedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
+typedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer);
+typedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);
+typedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);
+typedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IARBPROC) (GLint x, GLint y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVARBPROC) (const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVARBPROC) (const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVARBPROC) (const GLint *v);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);
+typedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVARBPROC) (const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1BOESPROC) (GLbyte s);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLVERTEX2BOESPROC) (GLbyte x);
+typedef void (APIENTRYP RGLSYMGLVERTEX2BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLVERTEX3BOESPROC) (GLbyte x, GLbyte y);
+typedef void (APIENTRYP RGLSYMGLVERTEX3BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z);
+typedef void (APIENTRYP RGLSYMGLVERTEX4BVOESPROC) (const GLbyte *coords);
+typedef void (APIENTRYP RGLSYMGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);
+typedef void (APIENTRYP RGLSYMGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP RGLSYMGLCLEARDEPTHXOESPROC) (GLfixed depth);
+typedef void (APIENTRYP RGLSYMGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
+typedef void (APIENTRYP RGLSYMGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP RGLSYMGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);
+typedef void (APIENTRYP RGLSYMGLFOGXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP RGLSYMGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);
+typedef void (APIENTRYP RGLSYMGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP RGLSYMGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLLINEWIDTHXOESPROC) (GLfixed width);
+typedef void (APIENTRYP RGLSYMGLLOADMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP RGLSYMGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);
+typedef void (APIENTRYP RGLSYMGLMULTMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (APIENTRYP RGLSYMGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
+typedef void (APIENTRYP RGLSYMGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);
+typedef void (APIENTRYP RGLSYMGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLPOINTSIZEXOESPROC) (GLfixed size);
+typedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
+typedef void (APIENTRYP RGLSYMGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert);
+typedef void (APIENTRYP RGLSYMGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP RGLSYMGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP RGLSYMGLACCUMXOESPROC) (GLenum op, GLfixed value);
+typedef void (APIENTRYP RGLSYMGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);
+typedef void (APIENTRYP RGLSYMGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP RGLSYMGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (APIENTRYP RGLSYMGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue);
+typedef void (APIENTRYP RGLSYMGLCOLOR3XVOESPROC) (const GLfixed *components);
+typedef void (APIENTRYP RGLSYMGLCOLOR4XVOESPROC) (const GLfixed *components);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLEVALCOORD1XOESPROC) (GLfixed u);
+typedef void (APIENTRYP RGLSYMGLEVALCOORD1XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v);
+typedef void (APIENTRYP RGLSYMGLEVALCOORD2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer);
+typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v);
+typedef void (APIENTRYP RGLSYMGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values);
+typedef void (APIENTRYP RGLSYMGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLINDEXXOESPROC) (GLfixed component);
+typedef void (APIENTRYP RGLSYMGLINDEXXVOESPROC) (const GLfixed *component);
+typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP RGLSYMGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);
+typedef void (APIENTRYP RGLSYMGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);
+typedef void (APIENTRYP RGLSYMGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2);
+typedef void (APIENTRYP RGLSYMGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);
+typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLNORMAL3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLPASSTHROUGHXOESPROC) (GLfixed token);
+typedef void (APIENTRYP RGLSYMGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values);
+typedef void (APIENTRYP RGLSYMGLPIXELSTOREXPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor);
+typedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities);
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y);
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w);
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);
+typedef void (APIENTRYP RGLSYMGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1XOESPROC) (GLfixed s);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
+typedef void (APIENTRYP RGLSYMGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
+typedef void (APIENTRYP RGLSYMGLVERTEX2XOESPROC) (GLfixed x);
+typedef void (APIENTRYP RGLSYMGLVERTEX2XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLVERTEX3XOESPROC) (GLfixed x, GLfixed y);
+typedef void (APIENTRYP RGLSYMGLVERTEX3XVOESPROC) (const GLfixed *coords);
+typedef void (APIENTRYP RGLSYMGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (APIENTRYP RGLSYMGLVERTEX4XVOESPROC) (const GLfixed *coords);
+typedef GLbitfield (APIENTRYP RGLSYMGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);
+typedef void (APIENTRYP RGLSYMGLCLEARDEPTHFOESPROC) (GLclampf depth);
+typedef void (APIENTRYP RGLSYMGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
+typedef void (APIENTRYP RGLSYMGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
+typedef void (APIENTRYP RGLSYMGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);
+typedef void (APIENTRYP RGLSYMGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
+typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);
+typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);
+
+#define glDrawRangeElements __rglgen_glDrawRangeElements
+#define glTexImage3D __rglgen_glTexImage3D
+#define glTexSubImage3D __rglgen_glTexSubImage3D
+#define glCopyTexSubImage3D __rglgen_glCopyTexSubImage3D
+#define glActiveTexture __rglgen_glActiveTexture
+#define glSampleCoverage __rglgen_glSampleCoverage
+#define glCompressedTexImage3D __rglgen_glCompressedTexImage3D
+#define glCompressedTexImage2D __rglgen_glCompressedTexImage2D
+#define glCompressedTexImage1D __rglgen_glCompressedTexImage1D
+#define glCompressedTexSubImage3D __rglgen_glCompressedTexSubImage3D
+#define glCompressedTexSubImage2D __rglgen_glCompressedTexSubImage2D
+#define glCompressedTexSubImage1D __rglgen_glCompressedTexSubImage1D
+#define glGetCompressedTexImage __rglgen_glGetCompressedTexImage
+#define glClientActiveTexture __rglgen_glClientActiveTexture
+#define glMultiTexCoord1d __rglgen_glMultiTexCoord1d
+#define glMultiTexCoord1dv __rglgen_glMultiTexCoord1dv
+#define glMultiTexCoord1f __rglgen_glMultiTexCoord1f
+#define glMultiTexCoord1fv __rglgen_glMultiTexCoord1fv
+#define glMultiTexCoord1i __rglgen_glMultiTexCoord1i
+#define glMultiTexCoord1iv __rglgen_glMultiTexCoord1iv
+#define glMultiTexCoord1s __rglgen_glMultiTexCoord1s
+#define glMultiTexCoord1sv __rglgen_glMultiTexCoord1sv
+#define glMultiTexCoord2d __rglgen_glMultiTexCoord2d
+#define glMultiTexCoord2dv __rglgen_glMultiTexCoord2dv
+#define glMultiTexCoord2f __rglgen_glMultiTexCoord2f
+#define glMultiTexCoord2fv __rglgen_glMultiTexCoord2fv
+#define glMultiTexCoord2i __rglgen_glMultiTexCoord2i
+#define glMultiTexCoord2iv __rglgen_glMultiTexCoord2iv
+#define glMultiTexCoord2s __rglgen_glMultiTexCoord2s
+#define glMultiTexCoord2sv __rglgen_glMultiTexCoord2sv
+#define glMultiTexCoord3d __rglgen_glMultiTexCoord3d
+#define glMultiTexCoord3dv __rglgen_glMultiTexCoord3dv
+#define glMultiTexCoord3f __rglgen_glMultiTexCoord3f
+#define glMultiTexCoord3fv __rglgen_glMultiTexCoord3fv
+#define glMultiTexCoord3i __rglgen_glMultiTexCoord3i
+#define glMultiTexCoord3iv __rglgen_glMultiTexCoord3iv
+#define glMultiTexCoord3s __rglgen_glMultiTexCoord3s
+#define glMultiTexCoord3sv __rglgen_glMultiTexCoord3sv
+#define glMultiTexCoord4d __rglgen_glMultiTexCoord4d
+#define glMultiTexCoord4dv __rglgen_glMultiTexCoord4dv
+#define glMultiTexCoord4f __rglgen_glMultiTexCoord4f
+#define glMultiTexCoord4fv __rglgen_glMultiTexCoord4fv
+#define glMultiTexCoord4i __rglgen_glMultiTexCoord4i
+#define glMultiTexCoord4iv __rglgen_glMultiTexCoord4iv
+#define glMultiTexCoord4s __rglgen_glMultiTexCoord4s
+#define glMultiTexCoord4sv __rglgen_glMultiTexCoord4sv
+#define glLoadTransposeMatrixf __rglgen_glLoadTransposeMatrixf
+#define glLoadTransposeMatrixd __rglgen_glLoadTransposeMatrixd
+#define glMultTransposeMatrixf __rglgen_glMultTransposeMatrixf
+#define glMultTransposeMatrixd __rglgen_glMultTransposeMatrixd
+#define glBlendFuncSeparate __rglgen_glBlendFuncSeparate
+#define glMultiDrawArrays __rglgen_glMultiDrawArrays
+#define glMultiDrawElements __rglgen_glMultiDrawElements
+#define glPointParameterf __rglgen_glPointParameterf
+#define glPointParameterfv __rglgen_glPointParameterfv
+#define glPointParameteri __rglgen_glPointParameteri
+#define glPointParameteriv __rglgen_glPointParameteriv
+#define glFogCoordf __rglgen_glFogCoordf
+#define glFogCoordfv __rglgen_glFogCoordfv
+#define glFogCoordd __rglgen_glFogCoordd
+#define glFogCoorddv __rglgen_glFogCoorddv
+#define glFogCoordPointer __rglgen_glFogCoordPointer
+#define glSecondaryColor3b __rglgen_glSecondaryColor3b
+#define glSecondaryColor3bv __rglgen_glSecondaryColor3bv
+#define glSecondaryColor3d __rglgen_glSecondaryColor3d
+#define glSecondaryColor3dv __rglgen_glSecondaryColor3dv
+#define glSecondaryColor3f __rglgen_glSecondaryColor3f
+#define glSecondaryColor3fv __rglgen_glSecondaryColor3fv
+#define glSecondaryColor3i __rglgen_glSecondaryColor3i
+#define glSecondaryColor3iv __rglgen_glSecondaryColor3iv
+#define glSecondaryColor3s __rglgen_glSecondaryColor3s
+#define glSecondaryColor3sv __rglgen_glSecondaryColor3sv
+#define glSecondaryColor3ub __rglgen_glSecondaryColor3ub
+#define glSecondaryColor3ubv __rglgen_glSecondaryColor3ubv
+#define glSecondaryColor3ui __rglgen_glSecondaryColor3ui
+#define glSecondaryColor3uiv __rglgen_glSecondaryColor3uiv
+#define glSecondaryColor3us __rglgen_glSecondaryColor3us
+#define glSecondaryColor3usv __rglgen_glSecondaryColor3usv
+#define glSecondaryColorPointer __rglgen_glSecondaryColorPointer
+#define glWindowPos2d __rglgen_glWindowPos2d
+#define glWindowPos2dv __rglgen_glWindowPos2dv
+#define glWindowPos2f __rglgen_glWindowPos2f
+#define glWindowPos2fv __rglgen_glWindowPos2fv
+#define glWindowPos2i __rglgen_glWindowPos2i
+#define glWindowPos2iv __rglgen_glWindowPos2iv
+#define glWindowPos2s __rglgen_glWindowPos2s
+#define glWindowPos2sv __rglgen_glWindowPos2sv
+#define glWindowPos3d __rglgen_glWindowPos3d
+#define glWindowPos3dv __rglgen_glWindowPos3dv
+#define glWindowPos3f __rglgen_glWindowPos3f
+#define glWindowPos3fv __rglgen_glWindowPos3fv
+#define glWindowPos3i __rglgen_glWindowPos3i
+#define glWindowPos3iv __rglgen_glWindowPos3iv
+#define glWindowPos3s __rglgen_glWindowPos3s
+#define glWindowPos3sv __rglgen_glWindowPos3sv
+#define glBlendColor __rglgen_glBlendColor
+#define glBlendEquation __rglgen_glBlendEquation
+#define glGenQueries __rglgen_glGenQueries
+#define glDeleteQueries __rglgen_glDeleteQueries
+#define glIsQuery __rglgen_glIsQuery
+#define glBeginQuery __rglgen_glBeginQuery
+#define glEndQuery __rglgen_glEndQuery
+#define glGetQueryiv __rglgen_glGetQueryiv
+#define glGetQueryObjectiv __rglgen_glGetQueryObjectiv
+#define glGetQueryObjectuiv __rglgen_glGetQueryObjectuiv
+#define glBindBuffer __rglgen_glBindBuffer
+#define glDeleteBuffers __rglgen_glDeleteBuffers
+#define glGenBuffers __rglgen_glGenBuffers
+#define glIsBuffer __rglgen_glIsBuffer
+#define glBufferData __rglgen_glBufferData
+#define glBufferSubData __rglgen_glBufferSubData
+#define glGetBufferSubData __rglgen_glGetBufferSubData
+#define glMapBuffer __rglgen_glMapBuffer
+#define glUnmapBuffer __rglgen_glUnmapBuffer
+#define glGetBufferParameteriv __rglgen_glGetBufferParameteriv
+#define glGetBufferPointerv __rglgen_glGetBufferPointerv
+#define glBlendEquationSeparate __rglgen_glBlendEquationSeparate
+#define glDrawBuffers __rglgen_glDrawBuffers
+#define glStencilOpSeparate __rglgen_glStencilOpSeparate
+#define glStencilFuncSeparate __rglgen_glStencilFuncSeparate
+#define glStencilMaskSeparate __rglgen_glStencilMaskSeparate
+#define glAttachShader __rglgen_glAttachShader
+#define glBindAttribLocation __rglgen_glBindAttribLocation
+#define glCompileShader __rglgen_glCompileShader
+#define glCreateProgram __rglgen_glCreateProgram
+#define glCreateShader __rglgen_glCreateShader
+#define glDeleteProgram __rglgen_glDeleteProgram
+#define glDeleteShader __rglgen_glDeleteShader
+#define glDetachShader __rglgen_glDetachShader
+#define glDisableVertexAttribArray __rglgen_glDisableVertexAttribArray
+#define glEnableVertexAttribArray __rglgen_glEnableVertexAttribArray
+#define glGetActiveAttrib __rglgen_glGetActiveAttrib
+#define glGetActiveUniform __rglgen_glGetActiveUniform
+#define glGetAttachedShaders __rglgen_glGetAttachedShaders
+#define glGetAttribLocation __rglgen_glGetAttribLocation
+#define glGetProgramiv __rglgen_glGetProgramiv
+#define glGetProgramInfoLog __rglgen_glGetProgramInfoLog
+#define glGetShaderiv __rglgen_glGetShaderiv
+#define glGetShaderInfoLog __rglgen_glGetShaderInfoLog
+#define glGetShaderSource __rglgen_glGetShaderSource
+#define glGetUniformLocation __rglgen_glGetUniformLocation
+#define glGetUniformfv __rglgen_glGetUniformfv
+#define glGetUniformiv __rglgen_glGetUniformiv
+#define glGetVertexAttribdv __rglgen_glGetVertexAttribdv
+#define glGetVertexAttribfv __rglgen_glGetVertexAttribfv
+#define glGetVertexAttribiv __rglgen_glGetVertexAttribiv
+#define glGetVertexAttribPointerv __rglgen_glGetVertexAttribPointerv
+#define glIsProgram __rglgen_glIsProgram
+#define glIsShader __rglgen_glIsShader
+#define glLinkProgram __rglgen_glLinkProgram
+#define glShaderSource __rglgen_glShaderSource
+#define glUseProgram __rglgen_glUseProgram
+#define glUniform1f __rglgen_glUniform1f
+#define glUniform2f __rglgen_glUniform2f
+#define glUniform3f __rglgen_glUniform3f
+#define glUniform4f __rglgen_glUniform4f
+#define glUniform1i __rglgen_glUniform1i
+#define glUniform2i __rglgen_glUniform2i
+#define glUniform3i __rglgen_glUniform3i
+#define glUniform4i __rglgen_glUniform4i
+#define glUniform1fv __rglgen_glUniform1fv
+#define glUniform2fv __rglgen_glUniform2fv
+#define glUniform3fv __rglgen_glUniform3fv
+#define glUniform4fv __rglgen_glUniform4fv
+#define glUniform1iv __rglgen_glUniform1iv
+#define glUniform2iv __rglgen_glUniform2iv
+#define glUniform3iv __rglgen_glUniform3iv
+#define glUniform4iv __rglgen_glUniform4iv
+#define glUniformMatrix2fv __rglgen_glUniformMatrix2fv
+#define glUniformMatrix3fv __rglgen_glUniformMatrix3fv
+#define glUniformMatrix4fv __rglgen_glUniformMatrix4fv
+#define glValidateProgram __rglgen_glValidateProgram
+#define glVertexAttrib1d __rglgen_glVertexAttrib1d
+#define glVertexAttrib1dv __rglgen_glVertexAttrib1dv
+#define glVertexAttrib1f __rglgen_glVertexAttrib1f
+#define glVertexAttrib1fv __rglgen_glVertexAttrib1fv
+#define glVertexAttrib1s __rglgen_glVertexAttrib1s
+#define glVertexAttrib1sv __rglgen_glVertexAttrib1sv
+#define glVertexAttrib2d __rglgen_glVertexAttrib2d
+#define glVertexAttrib2dv __rglgen_glVertexAttrib2dv
+#define glVertexAttrib2f __rglgen_glVertexAttrib2f
+#define glVertexAttrib2fv __rglgen_glVertexAttrib2fv
+#define glVertexAttrib2s __rglgen_glVertexAttrib2s
+#define glVertexAttrib2sv __rglgen_glVertexAttrib2sv
+#define glVertexAttrib3d __rglgen_glVertexAttrib3d
+#define glVertexAttrib3dv __rglgen_glVertexAttrib3dv
+#define glVertexAttrib3f __rglgen_glVertexAttrib3f
+#define glVertexAttrib3fv __rglgen_glVertexAttrib3fv
+#define glVertexAttrib3s __rglgen_glVertexAttrib3s
+#define glVertexAttrib3sv __rglgen_glVertexAttrib3sv
+#define glVertexAttrib4Nbv __rglgen_glVertexAttrib4Nbv
+#define glVertexAttrib4Niv __rglgen_glVertexAttrib4Niv
+#define glVertexAttrib4Nsv __rglgen_glVertexAttrib4Nsv
+#define glVertexAttrib4Nub __rglgen_glVertexAttrib4Nub
+#define glVertexAttrib4Nubv __rglgen_glVertexAttrib4Nubv
+#define glVertexAttrib4Nuiv __rglgen_glVertexAttrib4Nuiv
+#define glVertexAttrib4Nusv __rglgen_glVertexAttrib4Nusv
+#define glVertexAttrib4bv __rglgen_glVertexAttrib4bv
+#define glVertexAttrib4d __rglgen_glVertexAttrib4d
+#define glVertexAttrib4dv __rglgen_glVertexAttrib4dv
+#define glVertexAttrib4f __rglgen_glVertexAttrib4f
+#define glVertexAttrib4fv __rglgen_glVertexAttrib4fv
+#define glVertexAttrib4iv __rglgen_glVertexAttrib4iv
+#define glVertexAttrib4s __rglgen_glVertexAttrib4s
+#define glVertexAttrib4sv __rglgen_glVertexAttrib4sv
+#define glVertexAttrib4ubv __rglgen_glVertexAttrib4ubv
+#define glVertexAttrib4uiv __rglgen_glVertexAttrib4uiv
+#define glVertexAttrib4usv __rglgen_glVertexAttrib4usv
+#define glVertexAttribPointer __rglgen_glVertexAttribPointer
+#define glUniformMatrix2x3fv __rglgen_glUniformMatrix2x3fv
+#define glUniformMatrix3x2fv __rglgen_glUniformMatrix3x2fv
+#define glUniformMatrix2x4fv __rglgen_glUniformMatrix2x4fv
+#define glUniformMatrix4x2fv __rglgen_glUniformMatrix4x2fv
+#define glUniformMatrix3x4fv __rglgen_glUniformMatrix3x4fv
+#define glUniformMatrix4x3fv __rglgen_glUniformMatrix4x3fv
+#define glColorMaski __rglgen_glColorMaski
+#define glGetBooleani_v __rglgen_glGetBooleani_v
+#define glGetIntegeri_v __rglgen_glGetIntegeri_v
+#define glEnablei __rglgen_glEnablei
+#define glDisablei __rglgen_glDisablei
+#define glIsEnabledi __rglgen_glIsEnabledi
+#define glBeginTransformFeedback __rglgen_glBeginTransformFeedback
+#define glEndTransformFeedback __rglgen_glEndTransformFeedback
+#define glBindBufferRange __rglgen_glBindBufferRange
+#define glBindBufferBase __rglgen_glBindBufferBase
+#define glTransformFeedbackVaryings __rglgen_glTransformFeedbackVaryings
+#define glGetTransformFeedbackVarying __rglgen_glGetTransformFeedbackVarying
+#define glClampColor __rglgen_glClampColor
+#define glBeginConditionalRender __rglgen_glBeginConditionalRender
+#define glEndConditionalRender __rglgen_glEndConditionalRender
+#define glVertexAttribIPointer __rglgen_glVertexAttribIPointer
+#define glGetVertexAttribIiv __rglgen_glGetVertexAttribIiv
+#define glGetVertexAttribIuiv __rglgen_glGetVertexAttribIuiv
+#define glVertexAttribI1i __rglgen_glVertexAttribI1i
+#define glVertexAttribI2i __rglgen_glVertexAttribI2i
+#define glVertexAttribI3i __rglgen_glVertexAttribI3i
+#define glVertexAttribI4i __rglgen_glVertexAttribI4i
+#define glVertexAttribI1ui __rglgen_glVertexAttribI1ui
+#define glVertexAttribI2ui __rglgen_glVertexAttribI2ui
+#define glVertexAttribI3ui __rglgen_glVertexAttribI3ui
+#define glVertexAttribI4ui __rglgen_glVertexAttribI4ui
+#define glVertexAttribI1iv __rglgen_glVertexAttribI1iv
+#define glVertexAttribI2iv __rglgen_glVertexAttribI2iv
+#define glVertexAttribI3iv __rglgen_glVertexAttribI3iv
+#define glVertexAttribI4iv __rglgen_glVertexAttribI4iv
+#define glVertexAttribI1uiv __rglgen_glVertexAttribI1uiv
+#define glVertexAttribI2uiv __rglgen_glVertexAttribI2uiv
+#define glVertexAttribI3uiv __rglgen_glVertexAttribI3uiv
+#define glVertexAttribI4uiv __rglgen_glVertexAttribI4uiv
+#define glVertexAttribI4bv __rglgen_glVertexAttribI4bv
+#define glVertexAttribI4sv __rglgen_glVertexAttribI4sv
+#define glVertexAttribI4ubv __rglgen_glVertexAttribI4ubv
+#define glVertexAttribI4usv __rglgen_glVertexAttribI4usv
+#define glGetUniformuiv __rglgen_glGetUniformuiv
+#define glBindFragDataLocation __rglgen_glBindFragDataLocation
+#define glGetFragDataLocation __rglgen_glGetFragDataLocation
+#define glUniform1ui __rglgen_glUniform1ui
+#define glUniform2ui __rglgen_glUniform2ui
+#define glUniform3ui __rglgen_glUniform3ui
+#define glUniform4ui __rglgen_glUniform4ui
+#define glUniform1uiv __rglgen_glUniform1uiv
+#define glUniform2uiv __rglgen_glUniform2uiv
+#define glUniform3uiv __rglgen_glUniform3uiv
+#define glUniform4uiv __rglgen_glUniform4uiv
+#define glTexParameterIiv __rglgen_glTexParameterIiv
+#define glTexParameterIuiv __rglgen_glTexParameterIuiv
+#define glGetTexParameterIiv __rglgen_glGetTexParameterIiv
+#define glGetTexParameterIuiv __rglgen_glGetTexParameterIuiv
+#define glClearBufferiv __rglgen_glClearBufferiv
+#define glClearBufferuiv __rglgen_glClearBufferuiv
+#define glClearBufferfv __rglgen_glClearBufferfv
+#define glClearBufferfi __rglgen_glClearBufferfi
+#define glGetStringi __rglgen_glGetStringi
+#define glIsRenderbuffer __rglgen_glIsRenderbuffer
+#define glBindRenderbuffer __rglgen_glBindRenderbuffer
+#define glDeleteRenderbuffers __rglgen_glDeleteRenderbuffers
+#define glGenRenderbuffers __rglgen_glGenRenderbuffers
+#define glRenderbufferStorage __rglgen_glRenderbufferStorage
+#define glGetRenderbufferParameteriv __rglgen_glGetRenderbufferParameteriv
+#define glIsFramebuffer __rglgen_glIsFramebuffer
+#define glBindFramebuffer __rglgen_glBindFramebuffer
+#define glDeleteFramebuffers __rglgen_glDeleteFramebuffers
+#define glGenFramebuffers __rglgen_glGenFramebuffers
+#define glCheckFramebufferStatus __rglgen_glCheckFramebufferStatus
+#define glFramebufferTexture1D __rglgen_glFramebufferTexture1D
+#define glFramebufferTexture2D __rglgen_glFramebufferTexture2D
+#define glFramebufferTexture3D __rglgen_glFramebufferTexture3D
+#define glFramebufferRenderbuffer __rglgen_glFramebufferRenderbuffer
+#define glGetFramebufferAttachmentParameteriv __rglgen_glGetFramebufferAttachmentParameteriv
+#define glGenerateMipmap __rglgen_glGenerateMipmap
+#define glBlitFramebuffer __rglgen_glBlitFramebuffer
+#define glRenderbufferStorageMultisample __rglgen_glRenderbufferStorageMultisample
+#define glFramebufferTextureLayer __rglgen_glFramebufferTextureLayer
+#define glMapBufferRange __rglgen_glMapBufferRange
+#define glFlushMappedBufferRange __rglgen_glFlushMappedBufferRange
+#define glBindVertexArray __rglgen_glBindVertexArray
+#define glDeleteVertexArrays __rglgen_glDeleteVertexArrays
+#define glGenVertexArrays __rglgen_glGenVertexArrays
+#define glIsVertexArray __rglgen_glIsVertexArray
+#define glDrawArraysInstanced __rglgen_glDrawArraysInstanced
+#define glDrawElementsInstanced __rglgen_glDrawElementsInstanced
+#define glTexBuffer __rglgen_glTexBuffer
+#define glPrimitiveRestartIndex __rglgen_glPrimitiveRestartIndex
+#define glCopyBufferSubData __rglgen_glCopyBufferSubData
+#define glGetUniformIndices __rglgen_glGetUniformIndices
+#define glGetActiveUniformsiv __rglgen_glGetActiveUniformsiv
+#define glGetActiveUniformName __rglgen_glGetActiveUniformName
+#define glGetUniformBlockIndex __rglgen_glGetUniformBlockIndex
+#define glGetActiveUniformBlockiv __rglgen_glGetActiveUniformBlockiv
+#define glGetActiveUniformBlockName __rglgen_glGetActiveUniformBlockName
+#define glUniformBlockBinding __rglgen_glUniformBlockBinding
+#define glDrawElementsBaseVertex __rglgen_glDrawElementsBaseVertex
+#define glDrawRangeElementsBaseVertex __rglgen_glDrawRangeElementsBaseVertex
+#define glDrawElementsInstancedBaseVertex __rglgen_glDrawElementsInstancedBaseVertex
+#define glMultiDrawElementsBaseVertex __rglgen_glMultiDrawElementsBaseVertex
+#define glProvokingVertex __rglgen_glProvokingVertex
+#define glFenceSync __rglgen_glFenceSync
+#define glIsSync __rglgen_glIsSync
+#define glDeleteSync __rglgen_glDeleteSync
+#define glClientWaitSync __rglgen_glClientWaitSync
+#define glWaitSync __rglgen_glWaitSync
+#define glGetInteger64v __rglgen_glGetInteger64v
+#define glGetSynciv __rglgen_glGetSynciv
+#define glGetInteger64i_v __rglgen_glGetInteger64i_v
+#define glGetBufferParameteri64v __rglgen_glGetBufferParameteri64v
+#define glFramebufferTexture __rglgen_glFramebufferTexture
+#define glTexImage2DMultisample __rglgen_glTexImage2DMultisample
+#define glTexImage3DMultisample __rglgen_glTexImage3DMultisample
+#define glGetMultisamplefv __rglgen_glGetMultisamplefv
+#define glSampleMaski __rglgen_glSampleMaski
+#define glBindFragDataLocationIndexed __rglgen_glBindFragDataLocationIndexed
+#define glGetFragDataIndex __rglgen_glGetFragDataIndex
+#define glGenSamplers __rglgen_glGenSamplers
+#define glDeleteSamplers __rglgen_glDeleteSamplers
+#define glIsSampler __rglgen_glIsSampler
+#define glBindSampler __rglgen_glBindSampler
+#define glSamplerParameteri __rglgen_glSamplerParameteri
+#define glSamplerParameteriv __rglgen_glSamplerParameteriv
+#define glSamplerParameterf __rglgen_glSamplerParameterf
+#define glSamplerParameterfv __rglgen_glSamplerParameterfv
+#define glSamplerParameterIiv __rglgen_glSamplerParameterIiv
+#define glSamplerParameterIuiv __rglgen_glSamplerParameterIuiv
+#define glGetSamplerParameteriv __rglgen_glGetSamplerParameteriv
+#define glGetSamplerParameterIiv __rglgen_glGetSamplerParameterIiv
+#define glGetSamplerParameterfv __rglgen_glGetSamplerParameterfv
+#define glGetSamplerParameterIuiv __rglgen_glGetSamplerParameterIuiv
+#define glQueryCounter __rglgen_glQueryCounter
+#define glGetQueryObjecti64v __rglgen_glGetQueryObjecti64v
+#define glGetQueryObjectui64v __rglgen_glGetQueryObjectui64v
+#define glVertexAttribDivisor __rglgen_glVertexAttribDivisor
+#define glVertexAttribP1ui __rglgen_glVertexAttribP1ui
+#define glVertexAttribP1uiv __rglgen_glVertexAttribP1uiv
+#define glVertexAttribP2ui __rglgen_glVertexAttribP2ui
+#define glVertexAttribP2uiv __rglgen_glVertexAttribP2uiv
+#define glVertexAttribP3ui __rglgen_glVertexAttribP3ui
+#define glVertexAttribP3uiv __rglgen_glVertexAttribP3uiv
+#define glVertexAttribP4ui __rglgen_glVertexAttribP4ui
+#define glVertexAttribP4uiv __rglgen_glVertexAttribP4uiv
+#define glVertexP2ui __rglgen_glVertexP2ui
+#define glVertexP2uiv __rglgen_glVertexP2uiv
+#define glVertexP3ui __rglgen_glVertexP3ui
+#define glVertexP3uiv __rglgen_glVertexP3uiv
+#define glVertexP4ui __rglgen_glVertexP4ui
+#define glVertexP4uiv __rglgen_glVertexP4uiv
+#define glTexCoordP1ui __rglgen_glTexCoordP1ui
+#define glTexCoordP1uiv __rglgen_glTexCoordP1uiv
+#define glTexCoordP2ui __rglgen_glTexCoordP2ui
+#define glTexCoordP2uiv __rglgen_glTexCoordP2uiv
+#define glTexCoordP3ui __rglgen_glTexCoordP3ui
+#define glTexCoordP3uiv __rglgen_glTexCoordP3uiv
+#define glTexCoordP4ui __rglgen_glTexCoordP4ui
+#define glTexCoordP4uiv __rglgen_glTexCoordP4uiv
+#define glMultiTexCoordP1ui __rglgen_glMultiTexCoordP1ui
+#define glMultiTexCoordP1uiv __rglgen_glMultiTexCoordP1uiv
+#define glMultiTexCoordP2ui __rglgen_glMultiTexCoordP2ui
+#define glMultiTexCoordP2uiv __rglgen_glMultiTexCoordP2uiv
+#define glMultiTexCoordP3ui __rglgen_glMultiTexCoordP3ui
+#define glMultiTexCoordP3uiv __rglgen_glMultiTexCoordP3uiv
+#define glMultiTexCoordP4ui __rglgen_glMultiTexCoordP4ui
+#define glMultiTexCoordP4uiv __rglgen_glMultiTexCoordP4uiv
+#define glNormalP3ui __rglgen_glNormalP3ui
+#define glNormalP3uiv __rglgen_glNormalP3uiv
+#define glColorP3ui __rglgen_glColorP3ui
+#define glColorP3uiv __rglgen_glColorP3uiv
+#define glColorP4ui __rglgen_glColorP4ui
+#define glColorP4uiv __rglgen_glColorP4uiv
+#define glSecondaryColorP3ui __rglgen_glSecondaryColorP3ui
+#define glSecondaryColorP3uiv __rglgen_glSecondaryColorP3uiv
+#define glMinSampleShading __rglgen_glMinSampleShading
+#define glBlendEquationi __rglgen_glBlendEquationi
+#define glBlendEquationSeparatei __rglgen_glBlendEquationSeparatei
+#define glBlendFunci __rglgen_glBlendFunci
+#define glBlendFuncSeparatei __rglgen_glBlendFuncSeparatei
+#define glDrawArraysIndirect __rglgen_glDrawArraysIndirect
+#define glDrawElementsIndirect __rglgen_glDrawElementsIndirect
+#define glUniform1d __rglgen_glUniform1d
+#define glUniform2d __rglgen_glUniform2d
+#define glUniform3d __rglgen_glUniform3d
+#define glUniform4d __rglgen_glUniform4d
+#define glUniform1dv __rglgen_glUniform1dv
+#define glUniform2dv __rglgen_glUniform2dv
+#define glUniform3dv __rglgen_glUniform3dv
+#define glUniform4dv __rglgen_glUniform4dv
+#define glUniformMatrix2dv __rglgen_glUniformMatrix2dv
+#define glUniformMatrix3dv __rglgen_glUniformMatrix3dv
+#define glUniformMatrix4dv __rglgen_glUniformMatrix4dv
+#define glUniformMatrix2x3dv __rglgen_glUniformMatrix2x3dv
+#define glUniformMatrix2x4dv __rglgen_glUniformMatrix2x4dv
+#define glUniformMatrix3x2dv __rglgen_glUniformMatrix3x2dv
+#define glUniformMatrix3x4dv __rglgen_glUniformMatrix3x4dv
+#define glUniformMatrix4x2dv __rglgen_glUniformMatrix4x2dv
+#define glUniformMatrix4x3dv __rglgen_glUniformMatrix4x3dv
+#define glGetUniformdv __rglgen_glGetUniformdv
+#define glGetSubroutineUniformLocation __rglgen_glGetSubroutineUniformLocation
+#define glGetSubroutineIndex __rglgen_glGetSubroutineIndex
+#define glGetActiveSubroutineUniformiv __rglgen_glGetActiveSubroutineUniformiv
+#define glGetActiveSubroutineUniformName __rglgen_glGetActiveSubroutineUniformName
+#define glGetActiveSubroutineName __rglgen_glGetActiveSubroutineName
+#define glUniformSubroutinesuiv __rglgen_glUniformSubroutinesuiv
+#define glGetUniformSubroutineuiv __rglgen_glGetUniformSubroutineuiv
+#define glGetProgramStageiv __rglgen_glGetProgramStageiv
+#define glPatchParameteri __rglgen_glPatchParameteri
+#define glPatchParameterfv __rglgen_glPatchParameterfv
+#define glBindTransformFeedback __rglgen_glBindTransformFeedback
+#define glDeleteTransformFeedbacks __rglgen_glDeleteTransformFeedbacks
+#define glGenTransformFeedbacks __rglgen_glGenTransformFeedbacks
+#define glIsTransformFeedback __rglgen_glIsTransformFeedback
+#define glPauseTransformFeedback __rglgen_glPauseTransformFeedback
+#define glResumeTransformFeedback __rglgen_glResumeTransformFeedback
+#define glDrawTransformFeedback __rglgen_glDrawTransformFeedback
+#define glDrawTransformFeedbackStream __rglgen_glDrawTransformFeedbackStream
+#define glBeginQueryIndexed __rglgen_glBeginQueryIndexed
+#define glEndQueryIndexed __rglgen_glEndQueryIndexed
+#define glGetQueryIndexediv __rglgen_glGetQueryIndexediv
+#define glReleaseShaderCompiler __rglgen_glReleaseShaderCompiler
+#define glShaderBinary __rglgen_glShaderBinary
+#define glGetShaderPrecisionFormat __rglgen_glGetShaderPrecisionFormat
+#define glDepthRangef __rglgen_glDepthRangef
+#define glClearDepthf __rglgen_glClearDepthf
+#define glGetProgramBinary __rglgen_glGetProgramBinary
+#define glProgramBinary __rglgen_glProgramBinary
+#define glProgramParameteri __rglgen_glProgramParameteri
+#define glUseProgramStages __rglgen_glUseProgramStages
+#define glActiveShaderProgram __rglgen_glActiveShaderProgram
+#define glCreateShaderProgramv __rglgen_glCreateShaderProgramv
+#define glBindProgramPipeline __rglgen_glBindProgramPipeline
+#define glDeleteProgramPipelines __rglgen_glDeleteProgramPipelines
+#define glGenProgramPipelines __rglgen_glGenProgramPipelines
+#define glIsProgramPipeline __rglgen_glIsProgramPipeline
+#define glGetProgramPipelineiv __rglgen_glGetProgramPipelineiv
+#define glProgramUniform1i __rglgen_glProgramUniform1i
+#define glProgramUniform1iv __rglgen_glProgramUniform1iv
+#define glProgramUniform1f __rglgen_glProgramUniform1f
+#define glProgramUniform1fv __rglgen_glProgramUniform1fv
+#define glProgramUniform1d __rglgen_glProgramUniform1d
+#define glProgramUniform1dv __rglgen_glProgramUniform1dv
+#define glProgramUniform1ui __rglgen_glProgramUniform1ui
+#define glProgramUniform1uiv __rglgen_glProgramUniform1uiv
+#define glProgramUniform2i __rglgen_glProgramUniform2i
+#define glProgramUniform2iv __rglgen_glProgramUniform2iv
+#define glProgramUniform2f __rglgen_glProgramUniform2f
+#define glProgramUniform2fv __rglgen_glProgramUniform2fv
+#define glProgramUniform2d __rglgen_glProgramUniform2d
+#define glProgramUniform2dv __rglgen_glProgramUniform2dv
+#define glProgramUniform2ui __rglgen_glProgramUniform2ui
+#define glProgramUniform2uiv __rglgen_glProgramUniform2uiv
+#define glProgramUniform3i __rglgen_glProgramUniform3i
+#define glProgramUniform3iv __rglgen_glProgramUniform3iv
+#define glProgramUniform3f __rglgen_glProgramUniform3f
+#define glProgramUniform3fv __rglgen_glProgramUniform3fv
+#define glProgramUniform3d __rglgen_glProgramUniform3d
+#define glProgramUniform3dv __rglgen_glProgramUniform3dv
+#define glProgramUniform3ui __rglgen_glProgramUniform3ui
+#define glProgramUniform3uiv __rglgen_glProgramUniform3uiv
+#define glProgramUniform4i __rglgen_glProgramUniform4i
+#define glProgramUniform4iv __rglgen_glProgramUniform4iv
+#define glProgramUniform4f __rglgen_glProgramUniform4f
+#define glProgramUniform4fv __rglgen_glProgramUniform4fv
+#define glProgramUniform4d __rglgen_glProgramUniform4d
+#define glProgramUniform4dv __rglgen_glProgramUniform4dv
+#define glProgramUniform4ui __rglgen_glProgramUniform4ui
+#define glProgramUniform4uiv __rglgen_glProgramUniform4uiv
+#define glProgramUniformMatrix2fv __rglgen_glProgramUniformMatrix2fv
+#define glProgramUniformMatrix3fv __rglgen_glProgramUniformMatrix3fv
+#define glProgramUniformMatrix4fv __rglgen_glProgramUniformMatrix4fv
+#define glProgramUniformMatrix2dv __rglgen_glProgramUniformMatrix2dv
+#define glProgramUniformMatrix3dv __rglgen_glProgramUniformMatrix3dv
+#define glProgramUniformMatrix4dv __rglgen_glProgramUniformMatrix4dv
+#define glProgramUniformMatrix2x3fv __rglgen_glProgramUniformMatrix2x3fv
+#define glProgramUniformMatrix3x2fv __rglgen_glProgramUniformMatrix3x2fv
+#define glProgramUniformMatrix2x4fv __rglgen_glProgramUniformMatrix2x4fv
+#define glProgramUniformMatrix4x2fv __rglgen_glProgramUniformMatrix4x2fv
+#define glProgramUniformMatrix3x4fv __rglgen_glProgramUniformMatrix3x4fv
+#define glProgramUniformMatrix4x3fv __rglgen_glProgramUniformMatrix4x3fv
+#define glProgramUniformMatrix2x3dv __rglgen_glProgramUniformMatrix2x3dv
+#define glProgramUniformMatrix3x2dv __rglgen_glProgramUniformMatrix3x2dv
+#define glProgramUniformMatrix2x4dv __rglgen_glProgramUniformMatrix2x4dv
+#define glProgramUniformMatrix4x2dv __rglgen_glProgramUniformMatrix4x2dv
+#define glProgramUniformMatrix3x4dv __rglgen_glProgramUniformMatrix3x4dv
+#define glProgramUniformMatrix4x3dv __rglgen_glProgramUniformMatrix4x3dv
+#define glValidateProgramPipeline __rglgen_glValidateProgramPipeline
+#define glGetProgramPipelineInfoLog __rglgen_glGetProgramPipelineInfoLog
+#define glVertexAttribL1d __rglgen_glVertexAttribL1d
+#define glVertexAttribL2d __rglgen_glVertexAttribL2d
+#define glVertexAttribL3d __rglgen_glVertexAttribL3d
+#define glVertexAttribL4d __rglgen_glVertexAttribL4d
+#define glVertexAttribL1dv __rglgen_glVertexAttribL1dv
+#define glVertexAttribL2dv __rglgen_glVertexAttribL2dv
+#define glVertexAttribL3dv __rglgen_glVertexAttribL3dv
+#define glVertexAttribL4dv __rglgen_glVertexAttribL4dv
+#define glVertexAttribLPointer __rglgen_glVertexAttribLPointer
+#define glGetVertexAttribLdv __rglgen_glGetVertexAttribLdv
+#define glViewportArrayv __rglgen_glViewportArrayv
+#define glViewportIndexedf __rglgen_glViewportIndexedf
+#define glViewportIndexedfv __rglgen_glViewportIndexedfv
+#define glScissorArrayv __rglgen_glScissorArrayv
+#define glScissorIndexed __rglgen_glScissorIndexed
+#define glScissorIndexedv __rglgen_glScissorIndexedv
+#define glDepthRangeArrayv __rglgen_glDepthRangeArrayv
+#define glDepthRangeIndexed __rglgen_glDepthRangeIndexed
+#define glGetFloati_v __rglgen_glGetFloati_v
+#define glGetDoublei_v __rglgen_glGetDoublei_v
+#define glDrawArraysInstancedBaseInstance __rglgen_glDrawArraysInstancedBaseInstance
+#define glDrawElementsInstancedBaseInstance __rglgen_glDrawElementsInstancedBaseInstance
+#define glDrawElementsInstancedBaseVertexBaseInstance __rglgen_glDrawElementsInstancedBaseVertexBaseInstance
+#define glGetInternalformativ __rglgen_glGetInternalformativ
+#define glGetActiveAtomicCounterBufferiv __rglgen_glGetActiveAtomicCounterBufferiv
+#define glBindImageTexture __rglgen_glBindImageTexture
+#define glMemoryBarrier __rglgen_glMemoryBarrier
+#define glTexStorage1D __rglgen_glTexStorage1D
+#define glTexStorage2D __rglgen_glTexStorage2D
+#define glTexStorage3D __rglgen_glTexStorage3D
+#define glDrawTransformFeedbackInstanced __rglgen_glDrawTransformFeedbackInstanced
+#define glDrawTransformFeedbackStreamInstanced __rglgen_glDrawTransformFeedbackStreamInstanced
+#define glClearBufferData __rglgen_glClearBufferData
+#define glClearBufferSubData __rglgen_glClearBufferSubData
+#define glDispatchCompute __rglgen_glDispatchCompute
+#define glDispatchComputeIndirect __rglgen_glDispatchComputeIndirect
+#define glCopyImageSubData __rglgen_glCopyImageSubData
+#define glFramebufferParameteri __rglgen_glFramebufferParameteri
+#define glGetFramebufferParameteriv __rglgen_glGetFramebufferParameteriv
+#define glGetInternalformati64v __rglgen_glGetInternalformati64v
+#define glInvalidateTexSubImage __rglgen_glInvalidateTexSubImage
+#define glInvalidateTexImage __rglgen_glInvalidateTexImage
+#define glInvalidateBufferSubData __rglgen_glInvalidateBufferSubData
+#define glInvalidateBufferData __rglgen_glInvalidateBufferData
+#define glInvalidateFramebuffer __rglgen_glInvalidateFramebuffer
+#define glInvalidateSubFramebuffer __rglgen_glInvalidateSubFramebuffer
+#define glMultiDrawArraysIndirect __rglgen_glMultiDrawArraysIndirect
+#define glMultiDrawElementsIndirect __rglgen_glMultiDrawElementsIndirect
+#define glGetProgramInterfaceiv __rglgen_glGetProgramInterfaceiv
+#define glGetProgramResourceIndex __rglgen_glGetProgramResourceIndex
+#define glGetProgramResourceName __rglgen_glGetProgramResourceName
+#define glGetProgramResourceiv __rglgen_glGetProgramResourceiv
+#define glGetProgramResourceLocation __rglgen_glGetProgramResourceLocation
+#define glGetProgramResourceLocationIndex __rglgen_glGetProgramResourceLocationIndex
+#define glShaderStorageBlockBinding __rglgen_glShaderStorageBlockBinding
+#define glTexBufferRange __rglgen_glTexBufferRange
+#define glTexStorage2DMultisample __rglgen_glTexStorage2DMultisample
+#define glTexStorage3DMultisample __rglgen_glTexStorage3DMultisample
+#define glTextureView __rglgen_glTextureView
+#define glBindVertexBuffer __rglgen_glBindVertexBuffer
+#define glVertexAttribFormat __rglgen_glVertexAttribFormat
+#define glVertexAttribIFormat __rglgen_glVertexAttribIFormat
+#define glVertexAttribLFormat __rglgen_glVertexAttribLFormat
+#define glVertexAttribBinding __rglgen_glVertexAttribBinding
+#define glVertexBindingDivisor __rglgen_glVertexBindingDivisor
+#define glDebugMessageControl __rglgen_glDebugMessageControl
+#define glDebugMessageInsert __rglgen_glDebugMessageInsert
+#define glDebugMessageCallback __rglgen_glDebugMessageCallback
+#define glGetDebugMessageLog __rglgen_glGetDebugMessageLog
+#define glPushDebugGroup __rglgen_glPushDebugGroup
+#define glPopDebugGroup __rglgen_glPopDebugGroup
+#define glObjectLabel __rglgen_glObjectLabel
+#define glGetObjectLabel __rglgen_glGetObjectLabel
+#define glObjectPtrLabel __rglgen_glObjectPtrLabel
+#define glGetObjectPtrLabel __rglgen_glGetObjectPtrLabel
+#define glBufferStorage __rglgen_glBufferStorage
+#define glClearTexImage __rglgen_glClearTexImage
+#define glClearTexSubImage __rglgen_glClearTexSubImage
+#define glBindBuffersBase __rglgen_glBindBuffersBase
+#define glBindBuffersRange __rglgen_glBindBuffersRange
+#define glBindTextures __rglgen_glBindTextures
+#define glBindSamplers __rglgen_glBindSamplers
+#define glBindImageTextures __rglgen_glBindImageTextures
+#define glBindVertexBuffers __rglgen_glBindVertexBuffers
+#define glGetTextureHandleARB __rglgen_glGetTextureHandleARB
+#define glGetTextureSamplerHandleARB __rglgen_glGetTextureSamplerHandleARB
+#define glMakeTextureHandleResidentARB __rglgen_glMakeTextureHandleResidentARB
+#define glMakeTextureHandleNonResidentARB __rglgen_glMakeTextureHandleNonResidentARB
+#define glGetImageHandleARB __rglgen_glGetImageHandleARB
+#define glMakeImageHandleResidentARB __rglgen_glMakeImageHandleResidentARB
+#define glMakeImageHandleNonResidentARB __rglgen_glMakeImageHandleNonResidentARB
+#define glUniformHandleui64ARB __rglgen_glUniformHandleui64ARB
+#define glUniformHandleui64vARB __rglgen_glUniformHandleui64vARB
+#define glProgramUniformHandleui64ARB __rglgen_glProgramUniformHandleui64ARB
+#define glProgramUniformHandleui64vARB __rglgen_glProgramUniformHandleui64vARB
+#define glIsTextureHandleResidentARB __rglgen_glIsTextureHandleResidentARB
+#define glIsImageHandleResidentARB __rglgen_glIsImageHandleResidentARB
+#define glVertexAttribL1ui64ARB __rglgen_glVertexAttribL1ui64ARB
+#define glVertexAttribL1ui64vARB __rglgen_glVertexAttribL1ui64vARB
+#define glGetVertexAttribLui64vARB __rglgen_glGetVertexAttribLui64vARB
+#define glCreateSyncFromCLeventARB __rglgen_glCreateSyncFromCLeventARB
+#define glClampColorARB __rglgen_glClampColorARB
+#define glDispatchComputeGroupSizeARB __rglgen_glDispatchComputeGroupSizeARB
+#define glDebugMessageControlARB __rglgen_glDebugMessageControlARB
+#define glDebugMessageInsertARB __rglgen_glDebugMessageInsertARB
+#define glDebugMessageCallbackARB __rglgen_glDebugMessageCallbackARB
+#define glGetDebugMessageLogARB __rglgen_glGetDebugMessageLogARB
+#define glDrawBuffersARB __rglgen_glDrawBuffersARB
+#define glBlendEquationiARB __rglgen_glBlendEquationiARB
+#define glBlendEquationSeparateiARB __rglgen_glBlendEquationSeparateiARB
+#define glBlendFunciARB __rglgen_glBlendFunciARB
+#define glBlendFuncSeparateiARB __rglgen_glBlendFuncSeparateiARB
+#define glDrawArraysInstancedARB __rglgen_glDrawArraysInstancedARB
+#define glDrawElementsInstancedARB __rglgen_glDrawElementsInstancedARB
+#define glProgramStringARB __rglgen_glProgramStringARB
+#define glBindProgramARB __rglgen_glBindProgramARB
+#define glDeleteProgramsARB __rglgen_glDeleteProgramsARB
+#define glGenProgramsARB __rglgen_glGenProgramsARB
+#define glProgramEnvParameter4dARB __rglgen_glProgramEnvParameter4dARB
+#define glProgramEnvParameter4dvARB __rglgen_glProgramEnvParameter4dvARB
+#define glProgramEnvParameter4fARB __rglgen_glProgramEnvParameter4fARB
+#define glProgramEnvParameter4fvARB __rglgen_glProgramEnvParameter4fvARB
+#define glProgramLocalParameter4dARB __rglgen_glProgramLocalParameter4dARB
+#define glProgramLocalParameter4dvARB __rglgen_glProgramLocalParameter4dvARB
+#define glProgramLocalParameter4fARB __rglgen_glProgramLocalParameter4fARB
+#define glProgramLocalParameter4fvARB __rglgen_glProgramLocalParameter4fvARB
+#define glGetProgramEnvParameterdvARB __rglgen_glGetProgramEnvParameterdvARB
+#define glGetProgramEnvParameterfvARB __rglgen_glGetProgramEnvParameterfvARB
+#define glGetProgramLocalParameterdvARB __rglgen_glGetProgramLocalParameterdvARB
+#define glGetProgramLocalParameterfvARB __rglgen_glGetProgramLocalParameterfvARB
+#define glGetProgramivARB __rglgen_glGetProgramivARB
+#define glGetProgramStringARB __rglgen_glGetProgramStringARB
+#define glIsProgramARB __rglgen_glIsProgramARB
+#define glProgramParameteriARB __rglgen_glProgramParameteriARB
+#define glFramebufferTextureARB __rglgen_glFramebufferTextureARB
+#define glFramebufferTextureLayerARB __rglgen_glFramebufferTextureLayerARB
+#define glFramebufferTextureFaceARB __rglgen_glFramebufferTextureFaceARB
+#define glColorTable __rglgen_glColorTable
+#define glColorTableParameterfv __rglgen_glColorTableParameterfv
+#define glColorTableParameteriv __rglgen_glColorTableParameteriv
+#define glCopyColorTable __rglgen_glCopyColorTable
+#define glGetColorTable __rglgen_glGetColorTable
+#define glGetColorTableParameterfv __rglgen_glGetColorTableParameterfv
+#define glGetColorTableParameteriv __rglgen_glGetColorTableParameteriv
+#define glColorSubTable __rglgen_glColorSubTable
+#define glCopyColorSubTable __rglgen_glCopyColorSubTable
+#define glConvolutionFilter1D __rglgen_glConvolutionFilter1D
+#define glConvolutionFilter2D __rglgen_glConvolutionFilter2D
+#define glConvolutionParameterf __rglgen_glConvolutionParameterf
+#define glConvolutionParameterfv __rglgen_glConvolutionParameterfv
+#define glConvolutionParameteri __rglgen_glConvolutionParameteri
+#define glConvolutionParameteriv __rglgen_glConvolutionParameteriv
+#define glCopyConvolutionFilter1D __rglgen_glCopyConvolutionFilter1D
+#define glCopyConvolutionFilter2D __rglgen_glCopyConvolutionFilter2D
+#define glGetConvolutionFilter __rglgen_glGetConvolutionFilter
+#define glGetConvolutionParameterfv __rglgen_glGetConvolutionParameterfv
+#define glGetConvolutionParameteriv __rglgen_glGetConvolutionParameteriv
+#define glGetSeparableFilter __rglgen_glGetSeparableFilter
+#define glSeparableFilter2D __rglgen_glSeparableFilter2D
+#define glGetHistogram __rglgen_glGetHistogram
+#define glGetHistogramParameterfv __rglgen_glGetHistogramParameterfv
+#define glGetHistogramParameteriv __rglgen_glGetHistogramParameteriv
+#define glGetMinmax __rglgen_glGetMinmax
+#define glGetMinmaxParameterfv __rglgen_glGetMinmaxParameterfv
+#define glGetMinmaxParameteriv __rglgen_glGetMinmaxParameteriv
+#define glHistogram __rglgen_glHistogram
+#define glMinmax __rglgen_glMinmax
+#define glResetHistogram __rglgen_glResetHistogram
+#define glResetMinmax __rglgen_glResetMinmax
+#define glMultiDrawArraysIndirectCountARB __rglgen_glMultiDrawArraysIndirectCountARB
+#define glMultiDrawElementsIndirectCountARB __rglgen_glMultiDrawElementsIndirectCountARB
+#define glVertexAttribDivisorARB __rglgen_glVertexAttribDivisorARB
+#define glCurrentPaletteMatrixARB __rglgen_glCurrentPaletteMatrixARB
+#define glMatrixIndexubvARB __rglgen_glMatrixIndexubvARB
+#define glMatrixIndexusvARB __rglgen_glMatrixIndexusvARB
+#define glMatrixIndexuivARB __rglgen_glMatrixIndexuivARB
+#define glMatrixIndexPointerARB __rglgen_glMatrixIndexPointerARB
+#define glSampleCoverageARB __rglgen_glSampleCoverageARB
+#define glActiveTextureARB __rglgen_glActiveTextureARB
+#define glClientActiveTextureARB __rglgen_glClientActiveTextureARB
+#define glMultiTexCoord1dARB __rglgen_glMultiTexCoord1dARB
+#define glMultiTexCoord1dvARB __rglgen_glMultiTexCoord1dvARB
+#define glMultiTexCoord1fARB __rglgen_glMultiTexCoord1fARB
+#define glMultiTexCoord1fvARB __rglgen_glMultiTexCoord1fvARB
+#define glMultiTexCoord1iARB __rglgen_glMultiTexCoord1iARB
+#define glMultiTexCoord1ivARB __rglgen_glMultiTexCoord1ivARB
+#define glMultiTexCoord1sARB __rglgen_glMultiTexCoord1sARB
+#define glMultiTexCoord1svARB __rglgen_glMultiTexCoord1svARB
+#define glMultiTexCoord2dARB __rglgen_glMultiTexCoord2dARB
+#define glMultiTexCoord2dvARB __rglgen_glMultiTexCoord2dvARB
+#define glMultiTexCoord2fARB __rglgen_glMultiTexCoord2fARB
+#define glMultiTexCoord2fvARB __rglgen_glMultiTexCoord2fvARB
+#define glMultiTexCoord2iARB __rglgen_glMultiTexCoord2iARB
+#define glMultiTexCoord2ivARB __rglgen_glMultiTexCoord2ivARB
+#define glMultiTexCoord2sARB __rglgen_glMultiTexCoord2sARB
+#define glMultiTexCoord2svARB __rglgen_glMultiTexCoord2svARB
+#define glMultiTexCoord3dARB __rglgen_glMultiTexCoord3dARB
+#define glMultiTexCoord3dvARB __rglgen_glMultiTexCoord3dvARB
+#define glMultiTexCoord3fARB __rglgen_glMultiTexCoord3fARB
+#define glMultiTexCoord3fvARB __rglgen_glMultiTexCoord3fvARB
+#define glMultiTexCoord3iARB __rglgen_glMultiTexCoord3iARB
+#define glMultiTexCoord3ivARB __rglgen_glMultiTexCoord3ivARB
+#define glMultiTexCoord3sARB __rglgen_glMultiTexCoord3sARB
+#define glMultiTexCoord3svARB __rglgen_glMultiTexCoord3svARB
+#define glMultiTexCoord4dARB __rglgen_glMultiTexCoord4dARB
+#define glMultiTexCoord4dvARB __rglgen_glMultiTexCoord4dvARB
+#define glMultiTexCoord4fARB __rglgen_glMultiTexCoord4fARB
+#define glMultiTexCoord4fvARB __rglgen_glMultiTexCoord4fvARB
+#define glMultiTexCoord4iARB __rglgen_glMultiTexCoord4iARB
+#define glMultiTexCoord4ivARB __rglgen_glMultiTexCoord4ivARB
+#define glMultiTexCoord4sARB __rglgen_glMultiTexCoord4sARB
+#define glMultiTexCoord4svARB __rglgen_glMultiTexCoord4svARB
+#define glGenQueriesARB __rglgen_glGenQueriesARB
+#define glDeleteQueriesARB __rglgen_glDeleteQueriesARB
+#define glIsQueryARB __rglgen_glIsQueryARB
+#define glBeginQueryARB __rglgen_glBeginQueryARB
+#define glEndQueryARB __rglgen_glEndQueryARB
+#define glGetQueryivARB __rglgen_glGetQueryivARB
+#define glGetQueryObjectivARB __rglgen_glGetQueryObjectivARB
+#define glGetQueryObjectuivARB __rglgen_glGetQueryObjectuivARB
+#define glPointParameterfARB __rglgen_glPointParameterfARB
+#define glPointParameterfvARB __rglgen_glPointParameterfvARB
+#define glGetGraphicsResetStatusARB __rglgen_glGetGraphicsResetStatusARB
+#define glGetnTexImageARB __rglgen_glGetnTexImageARB
+#define glReadnPixelsARB __rglgen_glReadnPixelsARB
+#define glGetnCompressedTexImageARB __rglgen_glGetnCompressedTexImageARB
+#define glGetnUniformfvARB __rglgen_glGetnUniformfvARB
+#define glGetnUniformivARB __rglgen_glGetnUniformivARB
+#define glGetnUniformuivARB __rglgen_glGetnUniformuivARB
+#define glGetnUniformdvARB __rglgen_glGetnUniformdvARB
+#define glGetnMapdvARB __rglgen_glGetnMapdvARB
+#define glGetnMapfvARB __rglgen_glGetnMapfvARB
+#define glGetnMapivARB __rglgen_glGetnMapivARB
+#define glGetnPixelMapfvARB __rglgen_glGetnPixelMapfvARB
+#define glGetnPixelMapuivARB __rglgen_glGetnPixelMapuivARB
+#define glGetnPixelMapusvARB __rglgen_glGetnPixelMapusvARB
+#define glGetnPolygonStippleARB __rglgen_glGetnPolygonStippleARB
+#define glGetnColorTableARB __rglgen_glGetnColorTableARB
+#define glGetnConvolutionFilterARB __rglgen_glGetnConvolutionFilterARB
+#define glGetnSeparableFilterARB __rglgen_glGetnSeparableFilterARB
+#define glGetnHistogramARB __rglgen_glGetnHistogramARB
+#define glGetnMinmaxARB __rglgen_glGetnMinmaxARB
+#define glMinSampleShadingARB __rglgen_glMinSampleShadingARB
+#define glDeleteObjectARB __rglgen_glDeleteObjectARB
+#define glGetHandleARB __rglgen_glGetHandleARB
+#define glDetachObjectARB __rglgen_glDetachObjectARB
+#define glCreateShaderObjectARB __rglgen_glCreateShaderObjectARB
+#define glShaderSourceARB __rglgen_glShaderSourceARB
+#define glCompileShaderARB __rglgen_glCompileShaderARB
+#define glCreateProgramObjectARB __rglgen_glCreateProgramObjectARB
+#define glAttachObjectARB __rglgen_glAttachObjectARB
+#define glLinkProgramARB __rglgen_glLinkProgramARB
+#define glUseProgramObjectARB __rglgen_glUseProgramObjectARB
+#define glValidateProgramARB __rglgen_glValidateProgramARB
+#define glUniform1fARB __rglgen_glUniform1fARB
+#define glUniform2fARB __rglgen_glUniform2fARB
+#define glUniform3fARB __rglgen_glUniform3fARB
+#define glUniform4fARB __rglgen_glUniform4fARB
+#define glUniform1iARB __rglgen_glUniform1iARB
+#define glUniform2iARB __rglgen_glUniform2iARB
+#define glUniform3iARB __rglgen_glUniform3iARB
+#define glUniform4iARB __rglgen_glUniform4iARB
+#define glUniform1fvARB __rglgen_glUniform1fvARB
+#define glUniform2fvARB __rglgen_glUniform2fvARB
+#define glUniform3fvARB __rglgen_glUniform3fvARB
+#define glUniform4fvARB __rglgen_glUniform4fvARB
+#define glUniform1ivARB __rglgen_glUniform1ivARB
+#define glUniform2ivARB __rglgen_glUniform2ivARB
+#define glUniform3ivARB __rglgen_glUniform3ivARB
+#define glUniform4ivARB __rglgen_glUniform4ivARB
+#define glUniformMatrix2fvARB __rglgen_glUniformMatrix2fvARB
+#define glUniformMatrix3fvARB __rglgen_glUniformMatrix3fvARB
+#define glUniformMatrix4fvARB __rglgen_glUniformMatrix4fvARB
+#define glGetObjectParameterfvARB __rglgen_glGetObjectParameterfvARB
+#define glGetObjectParameterivARB __rglgen_glGetObjectParameterivARB
+#define glGetInfoLogARB __rglgen_glGetInfoLogARB
+#define glGetAttachedObjectsARB __rglgen_glGetAttachedObjectsARB
+#define glGetUniformLocationARB __rglgen_glGetUniformLocationARB
+#define glGetActiveUniformARB __rglgen_glGetActiveUniformARB
+#define glGetUniformfvARB __rglgen_glGetUniformfvARB
+#define glGetUniformivARB __rglgen_glGetUniformivARB
+#define glGetShaderSourceARB __rglgen_glGetShaderSourceARB
+#define glNamedStringARB __rglgen_glNamedStringARB
+#define glDeleteNamedStringARB __rglgen_glDeleteNamedStringARB
+#define glCompileShaderIncludeARB __rglgen_glCompileShaderIncludeARB
+#define glIsNamedStringARB __rglgen_glIsNamedStringARB
+#define glGetNamedStringARB __rglgen_glGetNamedStringARB
+#define glGetNamedStringivARB __rglgen_glGetNamedStringivARB
+#define glTexPageCommitmentARB __rglgen_glTexPageCommitmentARB
+#define glTexBufferARB __rglgen_glTexBufferARB
+#define glCompressedTexImage3DARB __rglgen_glCompressedTexImage3DARB
+#define glCompressedTexImage2DARB __rglgen_glCompressedTexImage2DARB
+#define glCompressedTexImage1DARB __rglgen_glCompressedTexImage1DARB
+#define glCompressedTexSubImage3DARB __rglgen_glCompressedTexSubImage3DARB
+#define glCompressedTexSubImage2DARB __rglgen_glCompressedTexSubImage2DARB
+#define glCompressedTexSubImage1DARB __rglgen_glCompressedTexSubImage1DARB
+#define glGetCompressedTexImageARB __rglgen_glGetCompressedTexImageARB
+#define glLoadTransposeMatrixfARB __rglgen_glLoadTransposeMatrixfARB
+#define glLoadTransposeMatrixdARB __rglgen_glLoadTransposeMatrixdARB
+#define glMultTransposeMatrixfARB __rglgen_glMultTransposeMatrixfARB
+#define glMultTransposeMatrixdARB __rglgen_glMultTransposeMatrixdARB
+#define glWeightbvARB __rglgen_glWeightbvARB
+#define glWeightsvARB __rglgen_glWeightsvARB
+#define glWeightivARB __rglgen_glWeightivARB
+#define glWeightfvARB __rglgen_glWeightfvARB
+#define glWeightdvARB __rglgen_glWeightdvARB
+#define glWeightubvARB __rglgen_glWeightubvARB
+#define glWeightusvARB __rglgen_glWeightusvARB
+#define glWeightuivARB __rglgen_glWeightuivARB
+#define glWeightPointerARB __rglgen_glWeightPointerARB
+#define glVertexBlendARB __rglgen_glVertexBlendARB
+#define glBindBufferARB __rglgen_glBindBufferARB
+#define glDeleteBuffersARB __rglgen_glDeleteBuffersARB
+#define glGenBuffersARB __rglgen_glGenBuffersARB
+#define glIsBufferARB __rglgen_glIsBufferARB
+#define glBufferDataARB __rglgen_glBufferDataARB
+#define glBufferSubDataARB __rglgen_glBufferSubDataARB
+#define glGetBufferSubDataARB __rglgen_glGetBufferSubDataARB
+#define glMapBufferARB __rglgen_glMapBufferARB
+#define glUnmapBufferARB __rglgen_glUnmapBufferARB
+#define glGetBufferParameterivARB __rglgen_glGetBufferParameterivARB
+#define glGetBufferPointervARB __rglgen_glGetBufferPointervARB
+#define glVertexAttrib1dARB __rglgen_glVertexAttrib1dARB
+#define glVertexAttrib1dvARB __rglgen_glVertexAttrib1dvARB
+#define glVertexAttrib1fARB __rglgen_glVertexAttrib1fARB
+#define glVertexAttrib1fvARB __rglgen_glVertexAttrib1fvARB
+#define glVertexAttrib1sARB __rglgen_glVertexAttrib1sARB
+#define glVertexAttrib1svARB __rglgen_glVertexAttrib1svARB
+#define glVertexAttrib2dARB __rglgen_glVertexAttrib2dARB
+#define glVertexAttrib2dvARB __rglgen_glVertexAttrib2dvARB
+#define glVertexAttrib2fARB __rglgen_glVertexAttrib2fARB
+#define glVertexAttrib2fvARB __rglgen_glVertexAttrib2fvARB
+#define glVertexAttrib2sARB __rglgen_glVertexAttrib2sARB
+#define glVertexAttrib2svARB __rglgen_glVertexAttrib2svARB
+#define glVertexAttrib3dARB __rglgen_glVertexAttrib3dARB
+#define glVertexAttrib3dvARB __rglgen_glVertexAttrib3dvARB
+#define glVertexAttrib3fARB __rglgen_glVertexAttrib3fARB
+#define glVertexAttrib3fvARB __rglgen_glVertexAttrib3fvARB
+#define glVertexAttrib3sARB __rglgen_glVertexAttrib3sARB
+#define glVertexAttrib3svARB __rglgen_glVertexAttrib3svARB
+#define glVertexAttrib4NbvARB __rglgen_glVertexAttrib4NbvARB
+#define glVertexAttrib4NivARB __rglgen_glVertexAttrib4NivARB
+#define glVertexAttrib4NsvARB __rglgen_glVertexAttrib4NsvARB
+#define glVertexAttrib4NubARB __rglgen_glVertexAttrib4NubARB
+#define glVertexAttrib4NubvARB __rglgen_glVertexAttrib4NubvARB
+#define glVertexAttrib4NuivARB __rglgen_glVertexAttrib4NuivARB
+#define glVertexAttrib4NusvARB __rglgen_glVertexAttrib4NusvARB
+#define glVertexAttrib4bvARB __rglgen_glVertexAttrib4bvARB
+#define glVertexAttrib4dARB __rglgen_glVertexAttrib4dARB
+#define glVertexAttrib4dvARB __rglgen_glVertexAttrib4dvARB
+#define glVertexAttrib4fARB __rglgen_glVertexAttrib4fARB
+#define glVertexAttrib4fvARB __rglgen_glVertexAttrib4fvARB
+#define glVertexAttrib4ivARB __rglgen_glVertexAttrib4ivARB
+#define glVertexAttrib4sARB __rglgen_glVertexAttrib4sARB
+#define glVertexAttrib4svARB __rglgen_glVertexAttrib4svARB
+#define glVertexAttrib4ubvARB __rglgen_glVertexAttrib4ubvARB
+#define glVertexAttrib4uivARB __rglgen_glVertexAttrib4uivARB
+#define glVertexAttrib4usvARB __rglgen_glVertexAttrib4usvARB
+#define glVertexAttribPointerARB __rglgen_glVertexAttribPointerARB
+#define glEnableVertexAttribArrayARB __rglgen_glEnableVertexAttribArrayARB
+#define glDisableVertexAttribArrayARB __rglgen_glDisableVertexAttribArrayARB
+#define glGetVertexAttribdvARB __rglgen_glGetVertexAttribdvARB
+#define glGetVertexAttribfvARB __rglgen_glGetVertexAttribfvARB
+#define glGetVertexAttribivARB __rglgen_glGetVertexAttribivARB
+#define glGetVertexAttribPointervARB __rglgen_glGetVertexAttribPointervARB
+#define glBindAttribLocationARB __rglgen_glBindAttribLocationARB
+#define glGetActiveAttribARB __rglgen_glGetActiveAttribARB
+#define glGetAttribLocationARB __rglgen_glGetAttribLocationARB
+#define glWindowPos2dARB __rglgen_glWindowPos2dARB
+#define glWindowPos2dvARB __rglgen_glWindowPos2dvARB
+#define glWindowPos2fARB __rglgen_glWindowPos2fARB
+#define glWindowPos2fvARB __rglgen_glWindowPos2fvARB
+#define glWindowPos2iARB __rglgen_glWindowPos2iARB
+#define glWindowPos2ivARB __rglgen_glWindowPos2ivARB
+#define glWindowPos2sARB __rglgen_glWindowPos2sARB
+#define glWindowPos2svARB __rglgen_glWindowPos2svARB
+#define glWindowPos3dARB __rglgen_glWindowPos3dARB
+#define glWindowPos3dvARB __rglgen_glWindowPos3dvARB
+#define glWindowPos3fARB __rglgen_glWindowPos3fARB
+#define glWindowPos3fvARB __rglgen_glWindowPos3fvARB
+#define glWindowPos3iARB __rglgen_glWindowPos3iARB
+#define glWindowPos3ivARB __rglgen_glWindowPos3ivARB
+#define glWindowPos3sARB __rglgen_glWindowPos3sARB
+#define glWindowPos3svARB __rglgen_glWindowPos3svARB
+#define glMultiTexCoord1bOES __rglgen_glMultiTexCoord1bOES
+#define glMultiTexCoord1bvOES __rglgen_glMultiTexCoord1bvOES
+#define glMultiTexCoord2bOES __rglgen_glMultiTexCoord2bOES
+#define glMultiTexCoord2bvOES __rglgen_glMultiTexCoord2bvOES
+#define glMultiTexCoord3bOES __rglgen_glMultiTexCoord3bOES
+#define glMultiTexCoord3bvOES __rglgen_glMultiTexCoord3bvOES
+#define glMultiTexCoord4bOES __rglgen_glMultiTexCoord4bOES
+#define glMultiTexCoord4bvOES __rglgen_glMultiTexCoord4bvOES
+#define glTexCoord1bOES __rglgen_glTexCoord1bOES
+#define glTexCoord1bvOES __rglgen_glTexCoord1bvOES
+#define glTexCoord2bOES __rglgen_glTexCoord2bOES
+#define glTexCoord2bvOES __rglgen_glTexCoord2bvOES
+#define glTexCoord3bOES __rglgen_glTexCoord3bOES
+#define glTexCoord3bvOES __rglgen_glTexCoord3bvOES
+#define glTexCoord4bOES __rglgen_glTexCoord4bOES
+#define glTexCoord4bvOES __rglgen_glTexCoord4bvOES
+#define glVertex2bOES __rglgen_glVertex2bOES
+#define glVertex2bvOES __rglgen_glVertex2bvOES
+#define glVertex3bOES __rglgen_glVertex3bOES
+#define glVertex3bvOES __rglgen_glVertex3bvOES
+#define glVertex4bOES __rglgen_glVertex4bOES
+#define glVertex4bvOES __rglgen_glVertex4bvOES
+#define glAlphaFuncxOES __rglgen_glAlphaFuncxOES
+#define glClearColorxOES __rglgen_glClearColorxOES
+#define glClearDepthxOES __rglgen_glClearDepthxOES
+#define glClipPlanexOES __rglgen_glClipPlanexOES
+#define glColor4xOES __rglgen_glColor4xOES
+#define glDepthRangexOES __rglgen_glDepthRangexOES
+#define glFogxOES __rglgen_glFogxOES
+#define glFogxvOES __rglgen_glFogxvOES
+#define glFrustumxOES __rglgen_glFrustumxOES
+#define glGetClipPlanexOES __rglgen_glGetClipPlanexOES
+#define glGetFixedvOES __rglgen_glGetFixedvOES
+#define glGetTexEnvxvOES __rglgen_glGetTexEnvxvOES
+#define glGetTexParameterxvOES __rglgen_glGetTexParameterxvOES
+#define glLightModelxOES __rglgen_glLightModelxOES
+#define glLightModelxvOES __rglgen_glLightModelxvOES
+#define glLightxOES __rglgen_glLightxOES
+#define glLightxvOES __rglgen_glLightxvOES
+#define glLineWidthxOES __rglgen_glLineWidthxOES
+#define glLoadMatrixxOES __rglgen_glLoadMatrixxOES
+#define glMaterialxOES __rglgen_glMaterialxOES
+#define glMaterialxvOES __rglgen_glMaterialxvOES
+#define glMultMatrixxOES __rglgen_glMultMatrixxOES
+#define glMultiTexCoord4xOES __rglgen_glMultiTexCoord4xOES
+#define glNormal3xOES __rglgen_glNormal3xOES
+#define glOrthoxOES __rglgen_glOrthoxOES
+#define glPointParameterxvOES __rglgen_glPointParameterxvOES
+#define glPointSizexOES __rglgen_glPointSizexOES
+#define glPolygonOffsetxOES __rglgen_glPolygonOffsetxOES
+#define glRotatexOES __rglgen_glRotatexOES
+#define glSampleCoverageOES __rglgen_glSampleCoverageOES
+#define glScalexOES __rglgen_glScalexOES
+#define glTexEnvxOES __rglgen_glTexEnvxOES
+#define glTexEnvxvOES __rglgen_glTexEnvxvOES
+#define glTexParameterxOES __rglgen_glTexParameterxOES
+#define glTexParameterxvOES __rglgen_glTexParameterxvOES
+#define glTranslatexOES __rglgen_glTranslatexOES
+#define glAccumxOES __rglgen_glAccumxOES
+#define glBitmapxOES __rglgen_glBitmapxOES
+#define glBlendColorxOES __rglgen_glBlendColorxOES
+#define glClearAccumxOES __rglgen_glClearAccumxOES
+#define glColor3xOES __rglgen_glColor3xOES
+#define glColor3xvOES __rglgen_glColor3xvOES
+#define glColor4xvOES __rglgen_glColor4xvOES
+#define glConvolutionParameterxOES __rglgen_glConvolutionParameterxOES
+#define glConvolutionParameterxvOES __rglgen_glConvolutionParameterxvOES
+#define glEvalCoord1xOES __rglgen_glEvalCoord1xOES
+#define glEvalCoord1xvOES __rglgen_glEvalCoord1xvOES
+#define glEvalCoord2xOES __rglgen_glEvalCoord2xOES
+#define glEvalCoord2xvOES __rglgen_glEvalCoord2xvOES
+#define glFeedbackBufferxOES __rglgen_glFeedbackBufferxOES
+#define glGetConvolutionParameterxvOES __rglgen_glGetConvolutionParameterxvOES
+#define glGetHistogramParameterxvOES __rglgen_glGetHistogramParameterxvOES
+#define glGetLightxOES __rglgen_glGetLightxOES
+#define glGetMapxvOES __rglgen_glGetMapxvOES
+#define glGetMaterialxOES __rglgen_glGetMaterialxOES
+#define glGetPixelMapxv __rglgen_glGetPixelMapxv
+#define glGetTexGenxvOES __rglgen_glGetTexGenxvOES
+#define glGetTexLevelParameterxvOES __rglgen_glGetTexLevelParameterxvOES
+#define glIndexxOES __rglgen_glIndexxOES
+#define glIndexxvOES __rglgen_glIndexxvOES
+#define glLoadTransposeMatrixxOES __rglgen_glLoadTransposeMatrixxOES
+#define glMap1xOES __rglgen_glMap1xOES
+#define glMap2xOES __rglgen_glMap2xOES
+#define glMapGrid1xOES __rglgen_glMapGrid1xOES
+#define glMapGrid2xOES __rglgen_glMapGrid2xOES
+#define glMultTransposeMatrixxOES __rglgen_glMultTransposeMatrixxOES
+#define glMultiTexCoord1xOES __rglgen_glMultiTexCoord1xOES
+#define glMultiTexCoord1xvOES __rglgen_glMultiTexCoord1xvOES
+#define glMultiTexCoord2xOES __rglgen_glMultiTexCoord2xOES
+#define glMultiTexCoord2xvOES __rglgen_glMultiTexCoord2xvOES
+#define glMultiTexCoord3xOES __rglgen_glMultiTexCoord3xOES
+#define glMultiTexCoord3xvOES __rglgen_glMultiTexCoord3xvOES
+#define glMultiTexCoord4xvOES __rglgen_glMultiTexCoord4xvOES
+#define glNormal3xvOES __rglgen_glNormal3xvOES
+#define glPassThroughxOES __rglgen_glPassThroughxOES
+#define glPixelMapx __rglgen_glPixelMapx
+#define glPixelStorex __rglgen_glPixelStorex
+#define glPixelTransferxOES __rglgen_glPixelTransferxOES
+#define glPixelZoomxOES __rglgen_glPixelZoomxOES
+#define glPrioritizeTexturesxOES __rglgen_glPrioritizeTexturesxOES
+#define glRasterPos2xOES __rglgen_glRasterPos2xOES
+#define glRasterPos2xvOES __rglgen_glRasterPos2xvOES
+#define glRasterPos3xOES __rglgen_glRasterPos3xOES
+#define glRasterPos3xvOES __rglgen_glRasterPos3xvOES
+#define glRasterPos4xOES __rglgen_glRasterPos4xOES
+#define glRasterPos4xvOES __rglgen_glRasterPos4xvOES
+#define glRectxOES __rglgen_glRectxOES
+#define glRectxvOES __rglgen_glRectxvOES
+#define glTexCoord1xOES __rglgen_glTexCoord1xOES
+#define glTexCoord1xvOES __rglgen_glTexCoord1xvOES
+#define glTexCoord2xOES __rglgen_glTexCoord2xOES
+#define glTexCoord2xvOES __rglgen_glTexCoord2xvOES
+#define glTexCoord3xOES __rglgen_glTexCoord3xOES
+#define glTexCoord3xvOES __rglgen_glTexCoord3xvOES
+#define glTexCoord4xOES __rglgen_glTexCoord4xOES
+#define glTexCoord4xvOES __rglgen_glTexCoord4xvOES
+#define glTexGenxOES __rglgen_glTexGenxOES
+#define glTexGenxvOES __rglgen_glTexGenxvOES
+#define glVertex2xOES __rglgen_glVertex2xOES
+#define glVertex2xvOES __rglgen_glVertex2xvOES
+#define glVertex3xOES __rglgen_glVertex3xOES
+#define glVertex3xvOES __rglgen_glVertex3xvOES
+#define glVertex4xOES __rglgen_glVertex4xOES
+#define glVertex4xvOES __rglgen_glVertex4xvOES
+#define glQueryMatrixxOES __rglgen_glQueryMatrixxOES
+#define glClearDepthfOES __rglgen_glClearDepthfOES
+#define glClipPlanefOES __rglgen_glClipPlanefOES
+#define glDepthRangefOES __rglgen_glDepthRangefOES
+#define glFrustumfOES __rglgen_glFrustumfOES
+#define glGetClipPlanefOES __rglgen_glGetClipPlanefOES
+#define glOrthofOES __rglgen_glOrthofOES
+#define glImageTransformParameteriHP __rglgen_glImageTransformParameteriHP
+#define glImageTransformParameterfHP __rglgen_glImageTransformParameterfHP
+#define glImageTransformParameterivHP __rglgen_glImageTransformParameterivHP
+#define glImageTransformParameterfvHP __rglgen_glImageTransformParameterfvHP
+#define glGetImageTransformParameterivHP __rglgen_glGetImageTransformParameterivHP
+#define glGetImageTransformParameterfvHP __rglgen_glGetImageTransformParameterfvHP
+
+extern RGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;
+extern RGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;
+extern RGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;
+extern RGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;
+extern RGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;
+extern RGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;
+extern RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;
+extern RGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;
+extern RGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;
+extern RGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;
+extern RGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;
+extern RGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;
+extern RGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;
+extern RGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;
+extern RGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;
+extern RGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;
+extern RGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;
+extern RGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;
+extern RGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;
+extern RGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;
+extern RGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;
+extern RGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;
+extern RGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;
+extern RGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;
+extern RGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;
+extern RGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;
+extern RGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;
+extern RGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;
+extern RGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;
+extern RGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;
+extern RGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;
+extern RGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;
+extern RGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;
+extern RGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;
+extern RGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;
+extern RGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;
+extern RGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;
+extern RGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;
+extern RGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;
+extern RGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;
+extern RGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;
+extern RGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;
+extern RGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;
+extern RGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;
+extern RGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;
+extern RGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;
+extern RGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;
+extern RGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;
+extern RGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;
+extern RGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;
+extern RGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;
+extern RGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;
+extern RGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;
+extern RGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;
+extern RGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;
+extern RGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;
+extern RGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;
+extern RGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;
+extern RGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;
+extern RGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;
+extern RGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;
+extern RGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;
+extern RGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;
+extern RGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;
+extern RGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;
+extern RGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;
+extern RGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;
+extern RGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;
+extern RGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;
+extern RGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;
+extern RGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;
+extern RGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;
+extern RGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;
+extern RGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;
+extern RGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;
+extern RGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;
+extern RGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;
+extern RGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;
+extern RGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;
+extern RGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;
+extern RGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;
+extern RGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;
+extern RGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;
+extern RGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;
+extern RGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;
+extern RGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;
+extern RGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;
+extern RGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;
+extern RGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;
+extern RGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;
+extern RGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;
+extern RGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;
+extern RGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;
+extern RGLSYMGLISQUERYPROC __rglgen_glIsQuery;
+extern RGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;
+extern RGLSYMGLENDQUERYPROC __rglgen_glEndQuery;
+extern RGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;
+extern RGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;
+extern RGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;
+extern RGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;
+extern RGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;
+extern RGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;
+extern RGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;
+extern RGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;
+extern RGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;
+extern RGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;
+extern RGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;
+extern RGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;
+extern RGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;
+extern RGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;
+extern RGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;
+extern RGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;
+extern RGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;
+extern RGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;
+extern RGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;
+extern RGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;
+extern RGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;
+extern RGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;
+extern RGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;
+extern RGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;
+extern RGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;
+extern RGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;
+extern RGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;
+extern RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;
+extern RGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;
+extern RGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;
+extern RGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;
+extern RGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;
+extern RGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;
+extern RGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;
+extern RGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;
+extern RGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;
+extern RGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;
+extern RGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;
+extern RGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;
+extern RGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;
+extern RGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;
+extern RGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;
+extern RGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;
+extern RGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;
+extern RGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;
+extern RGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;
+extern RGLSYMGLISSHADERPROC __rglgen_glIsShader;
+extern RGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;
+extern RGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;
+extern RGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;
+extern RGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;
+extern RGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;
+extern RGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;
+extern RGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;
+extern RGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;
+extern RGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;
+extern RGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;
+extern RGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;
+extern RGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;
+extern RGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;
+extern RGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;
+extern RGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;
+extern RGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;
+extern RGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;
+extern RGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;
+extern RGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;
+extern RGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;
+extern RGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;
+extern RGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;
+extern RGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;
+extern RGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;
+extern RGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;
+extern RGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;
+extern RGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;
+extern RGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;
+extern RGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;
+extern RGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;
+extern RGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;
+extern RGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;
+extern RGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;
+extern RGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;
+extern RGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;
+extern RGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;
+extern RGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;
+extern RGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;
+extern RGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;
+extern RGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;
+extern RGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;
+extern RGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;
+extern RGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;
+extern RGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;
+extern RGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;
+extern RGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;
+extern RGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;
+extern RGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;
+extern RGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;
+extern RGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;
+extern RGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;
+extern RGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;
+extern RGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;
+extern RGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;
+extern RGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;
+extern RGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;
+extern RGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;
+extern RGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;
+extern RGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;
+extern RGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;
+extern RGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;
+extern RGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;
+extern RGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;
+extern RGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;
+extern RGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;
+extern RGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;
+extern RGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;
+extern RGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;
+extern RGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;
+extern RGLSYMGLENABLEIPROC __rglgen_glEnablei;
+extern RGLSYMGLDISABLEIPROC __rglgen_glDisablei;
+extern RGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;
+extern RGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;
+extern RGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;
+extern RGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;
+extern RGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;
+extern RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;
+extern RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;
+extern RGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;
+extern RGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;
+extern RGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;
+extern RGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;
+extern RGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;
+extern RGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;
+extern RGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;
+extern RGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;
+extern RGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;
+extern RGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;
+extern RGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;
+extern RGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;
+extern RGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;
+extern RGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;
+extern RGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;
+extern RGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;
+extern RGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;
+extern RGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;
+extern RGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;
+extern RGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;
+extern RGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;
+extern RGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;
+extern RGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;
+extern RGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;
+extern RGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;
+extern RGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;
+extern RGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;
+extern RGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;
+extern RGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;
+extern RGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;
+extern RGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;
+extern RGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;
+extern RGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;
+extern RGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;
+extern RGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;
+extern RGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;
+extern RGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;
+extern RGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;
+extern RGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;
+extern RGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;
+extern RGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;
+extern RGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;
+extern RGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;
+extern RGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;
+extern RGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;
+extern RGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;
+extern RGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;
+extern RGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;
+extern RGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;
+extern RGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;
+extern RGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;
+extern RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;
+extern RGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;
+extern RGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;
+extern RGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;
+extern RGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;
+extern RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;
+extern RGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;
+extern RGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;
+extern RGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;
+extern RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;
+extern RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;
+extern RGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;
+extern RGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;
+extern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;
+extern RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;
+extern RGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;
+extern RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;
+extern RGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;
+extern RGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;
+extern RGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;
+extern RGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;
+extern RGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;
+extern RGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;
+extern RGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;
+extern RGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;
+extern RGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;
+extern RGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;
+extern RGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;
+extern RGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;
+extern RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;
+extern RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;
+extern RGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;
+extern RGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;
+extern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;
+extern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;
+extern RGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;
+extern RGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;
+extern RGLSYMGLISSYNCPROC __rglgen_glIsSync;
+extern RGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;
+extern RGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;
+extern RGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;
+extern RGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;
+extern RGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;
+extern RGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;
+extern RGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;
+extern RGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;
+extern RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;
+extern RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;
+extern RGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;
+extern RGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;
+extern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;
+extern RGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;
+extern RGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;
+extern RGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;
+extern RGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;
+extern RGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;
+extern RGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;
+extern RGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;
+extern RGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;
+extern RGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;
+extern RGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;
+extern RGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;
+extern RGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;
+extern RGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;
+extern RGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;
+extern RGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;
+extern RGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;
+extern RGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;
+extern RGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;
+extern RGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;
+extern RGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;
+extern RGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;
+extern RGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;
+extern RGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;
+extern RGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;
+extern RGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;
+extern RGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;
+extern RGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;
+extern RGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;
+extern RGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;
+extern RGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;
+extern RGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;
+extern RGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;
+extern RGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;
+extern RGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;
+extern RGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;
+extern RGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;
+extern RGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;
+extern RGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;
+extern RGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;
+extern RGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;
+extern RGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;
+extern RGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;
+extern RGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;
+extern RGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;
+extern RGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;
+extern RGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;
+extern RGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;
+extern RGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;
+extern RGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;
+extern RGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;
+extern RGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;
+extern RGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;
+extern RGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;
+extern RGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;
+extern RGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;
+extern RGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;
+extern RGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;
+extern RGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;
+extern RGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;
+extern RGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;
+extern RGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;
+extern RGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;
+extern RGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;
+extern RGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;
+extern RGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;
+extern RGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;
+extern RGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;
+extern RGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;
+extern RGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;
+extern RGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;
+extern RGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;
+extern RGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;
+extern RGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;
+extern RGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;
+extern RGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;
+extern RGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;
+extern RGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;
+extern RGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;
+extern RGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;
+extern RGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;
+extern RGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;
+extern RGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;
+extern RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;
+extern RGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;
+extern RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;
+extern RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;
+extern RGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;
+extern RGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;
+extern RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;
+extern RGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;
+extern RGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;
+extern RGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;
+extern RGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;
+extern RGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;
+extern RGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;
+extern RGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;
+extern RGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;
+extern RGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;
+extern RGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;
+extern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;
+extern RGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;
+extern RGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;
+extern RGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;
+extern RGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;
+extern RGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;
+extern RGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;
+extern RGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;
+extern RGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;
+extern RGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;
+extern RGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;
+extern RGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;
+extern RGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;
+extern RGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;
+extern RGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;
+extern RGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;
+extern RGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;
+extern RGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;
+extern RGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;
+extern RGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;
+extern RGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;
+extern RGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;
+extern RGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;
+extern RGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;
+extern RGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;
+extern RGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;
+extern RGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;
+extern RGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;
+extern RGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;
+extern RGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;
+extern RGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;
+extern RGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;
+extern RGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;
+extern RGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;
+extern RGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;
+extern RGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;
+extern RGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;
+extern RGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;
+extern RGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;
+extern RGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;
+extern RGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;
+extern RGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;
+extern RGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;
+extern RGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;
+extern RGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;
+extern RGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;
+extern RGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;
+extern RGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;
+extern RGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;
+extern RGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;
+extern RGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;
+extern RGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;
+extern RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;
+extern RGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;
+extern RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;
+extern RGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;
+extern RGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;
+extern RGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;
+extern RGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;
+extern RGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;
+extern RGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;
+extern RGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;
+extern RGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;
+extern RGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;
+extern RGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;
+extern RGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;
+extern RGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;
+extern RGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;
+extern RGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;
+extern RGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;
+extern RGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;
+extern RGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;
+extern RGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;
+extern RGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;
+extern RGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;
+extern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;
+extern RGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;
+extern RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;
+extern RGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;
+extern RGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;
+extern RGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;
+extern RGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;
+extern RGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;
+extern RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;
+extern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;
+extern RGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;
+extern RGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;
+extern RGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;
+extern RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;
+extern RGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;
+extern RGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;
+extern RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;
+extern RGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;
+extern RGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;
+extern RGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;
+extern RGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;
+extern RGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;
+extern RGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;
+extern RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;
+extern RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;
+extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;
+extern RGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;
+extern RGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;
+extern RGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;
+extern RGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;
+extern RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;
+extern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;
+extern RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;
+extern RGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;
+extern RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;
+extern RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;
+extern RGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;
+extern RGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;
+extern RGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;
+extern RGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;
+extern RGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;
+extern RGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;
+extern RGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;
+extern RGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;
+extern RGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;
+extern RGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;
+extern RGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;
+extern RGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;
+extern RGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;
+extern RGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;
+extern RGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;
+extern RGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;
+extern RGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;
+extern RGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;
+extern RGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;
+extern RGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;
+extern RGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;
+extern RGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;
+extern RGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;
+extern RGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;
+extern RGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;
+extern RGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;
+extern RGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;
+extern RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;
+extern RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;
+extern RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;
+extern RGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;
+extern RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;
+extern RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;
+extern RGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;
+extern RGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;
+extern RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;
+extern RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;
+extern RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;
+extern RGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;
+extern RGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;
+extern RGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;
+extern RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;
+extern RGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;
+extern RGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;
+extern RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;
+extern RGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;
+extern RGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;
+extern RGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;
+extern RGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;
+extern RGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;
+extern RGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;
+extern RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;
+extern RGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;
+extern RGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;
+extern RGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;
+extern RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;
+extern RGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;
+extern RGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;
+extern RGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;
+extern RGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;
+extern RGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;
+extern RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;
+extern RGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;
+extern RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;
+extern RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;
+extern RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;
+extern RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;
+extern RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;
+extern RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;
+extern RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;
+extern RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;
+extern RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;
+extern RGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;
+extern RGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;
+extern RGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;
+extern RGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;
+extern RGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;
+extern RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;
+extern RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;
+extern RGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;
+extern RGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;
+extern RGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;
+extern RGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;
+extern RGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;
+extern RGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;
+extern RGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;
+extern RGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;
+extern RGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;
+extern RGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;
+extern RGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;
+extern RGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;
+extern RGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;
+extern RGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;
+extern RGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;
+extern RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;
+extern RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;
+extern RGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;
+extern RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;
+extern RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;
+extern RGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;
+extern RGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;
+extern RGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;
+extern RGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;
+extern RGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;
+extern RGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;
+extern RGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;
+extern RGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;
+extern RGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;
+extern RGLSYMGLMINMAXPROC __rglgen_glMinmax;
+extern RGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;
+extern RGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;
+extern RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;
+extern RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;
+extern RGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;
+extern RGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;
+extern RGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;
+extern RGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;
+extern RGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;
+extern RGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;
+extern RGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;
+extern RGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;
+extern RGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;
+extern RGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;
+extern RGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;
+extern RGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;
+extern RGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;
+extern RGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;
+extern RGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;
+extern RGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;
+extern RGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;
+extern RGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;
+extern RGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;
+extern RGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;
+extern RGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;
+extern RGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;
+extern RGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;
+extern RGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;
+extern RGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;
+extern RGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;
+extern RGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;
+extern RGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;
+extern RGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;
+extern RGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;
+extern RGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;
+extern RGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;
+extern RGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;
+extern RGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;
+extern RGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;
+extern RGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;
+extern RGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;
+extern RGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;
+extern RGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;
+extern RGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;
+extern RGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;
+extern RGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;
+extern RGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;
+extern RGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;
+extern RGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;
+extern RGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;
+extern RGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;
+extern RGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;
+extern RGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;
+extern RGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;
+extern RGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;
+extern RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;
+extern RGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;
+extern RGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;
+extern RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;
+extern RGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;
+extern RGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;
+extern RGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;
+extern RGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;
+extern RGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;
+extern RGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;
+extern RGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;
+extern RGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;
+extern RGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;
+extern RGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;
+extern RGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;
+extern RGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;
+extern RGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;
+extern RGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;
+extern RGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;
+extern RGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;
+extern RGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;
+extern RGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;
+extern RGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;
+extern RGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;
+extern RGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;
+extern RGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;
+extern RGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;
+extern RGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;
+extern RGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;
+extern RGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;
+extern RGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;
+extern RGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;
+extern RGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;
+extern RGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;
+extern RGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;
+extern RGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;
+extern RGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;
+extern RGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;
+extern RGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;
+extern RGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;
+extern RGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;
+extern RGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;
+extern RGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;
+extern RGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;
+extern RGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;
+extern RGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;
+extern RGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;
+extern RGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;
+extern RGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;
+extern RGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;
+extern RGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;
+extern RGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;
+extern RGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;
+extern RGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;
+extern RGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;
+extern RGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;
+extern RGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;
+extern RGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;
+extern RGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;
+extern RGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;
+extern RGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;
+extern RGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;
+extern RGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;
+extern RGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;
+extern RGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;
+extern RGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;
+extern RGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;
+extern RGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;
+extern RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;
+extern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;
+extern RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;
+extern RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;
+extern RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;
+extern RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;
+extern RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;
+extern RGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;
+extern RGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;
+extern RGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;
+extern RGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;
+extern RGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;
+extern RGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;
+extern RGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;
+extern RGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;
+extern RGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;
+extern RGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;
+extern RGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;
+extern RGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;
+extern RGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;
+extern RGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;
+extern RGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;
+extern RGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;
+extern RGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;
+extern RGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;
+extern RGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;
+extern RGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;
+extern RGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;
+extern RGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;
+extern RGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;
+extern RGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;
+extern RGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;
+extern RGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;
+extern RGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;
+extern RGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;
+extern RGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;
+extern RGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;
+extern RGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;
+extern RGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;
+extern RGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;
+extern RGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;
+extern RGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;
+extern RGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;
+extern RGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;
+extern RGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;
+extern RGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;
+extern RGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;
+extern RGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;
+extern RGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;
+extern RGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;
+extern RGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;
+extern RGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;
+extern RGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;
+extern RGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;
+extern RGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;
+extern RGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;
+extern RGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;
+extern RGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;
+extern RGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;
+extern RGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;
+extern RGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;
+extern RGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;
+extern RGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;
+extern RGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;
+extern RGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;
+extern RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;
+extern RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;
+extern RGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;
+extern RGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;
+extern RGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;
+extern RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;
+extern RGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;
+extern RGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;
+extern RGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;
+extern RGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;
+extern RGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;
+extern RGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;
+extern RGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;
+extern RGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;
+extern RGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;
+extern RGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;
+extern RGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;
+extern RGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;
+extern RGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;
+extern RGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;
+extern RGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;
+extern RGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;
+extern RGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;
+extern RGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;
+extern RGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;
+extern RGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;
+extern RGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;
+extern RGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;
+extern RGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;
+extern RGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;
+extern RGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;
+extern RGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;
+extern RGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;
+extern RGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;
+extern RGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;
+extern RGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;
+extern RGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;
+extern RGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;
+extern RGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;
+extern RGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;
+extern RGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;
+extern RGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;
+extern RGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;
+extern RGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;
+extern RGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;
+extern RGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;
+extern RGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;
+extern RGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;
+extern RGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;
+extern RGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;
+extern RGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;
+extern RGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;
+extern RGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;
+extern RGLSYMGLFOGXOESPROC __rglgen_glFogxOES;
+extern RGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;
+extern RGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;
+extern RGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;
+extern RGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;
+extern RGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;
+extern RGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;
+extern RGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;
+extern RGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;
+extern RGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;
+extern RGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;
+extern RGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;
+extern RGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;
+extern RGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;
+extern RGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;
+extern RGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;
+extern RGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;
+extern RGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;
+extern RGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;
+extern RGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;
+extern RGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;
+extern RGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;
+extern RGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;
+extern RGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;
+extern RGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;
+extern RGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;
+extern RGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;
+extern RGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;
+extern RGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;
+extern RGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;
+extern RGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;
+extern RGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;
+extern RGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;
+extern RGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;
+extern RGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;
+extern RGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;
+extern RGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;
+extern RGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;
+extern RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;
+extern RGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;
+extern RGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;
+extern RGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;
+extern RGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;
+extern RGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;
+extern RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;
+extern RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;
+extern RGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;
+extern RGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;
+extern RGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;
+extern RGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;
+extern RGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;
+extern RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;
+extern RGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;
+extern RGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;
+extern RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;
+extern RGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;
+extern RGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;
+extern RGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;
+extern RGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;
+extern RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;
+extern RGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;
+extern RGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;
+extern RGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;
+extern RGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;
+extern RGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;
+extern RGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;
+extern RGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;
+extern RGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;
+extern RGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;
+extern RGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;
+extern RGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;
+extern RGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;
+extern RGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;
+extern RGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;
+extern RGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;
+extern RGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;
+extern RGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;
+extern RGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;
+extern RGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;
+extern RGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;
+extern RGLSYMGLRECTXOESPROC __rglgen_glRectxOES;
+extern RGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;
+extern RGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;
+extern RGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;
+extern RGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;
+extern RGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;
+extern RGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;
+extern RGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;
+extern RGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;
+extern RGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;
+extern RGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;
+extern RGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;
+extern RGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;
+extern RGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;
+extern RGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;
+extern RGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;
+extern RGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;
+extern RGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;
+extern RGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;
+extern RGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;
+extern RGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;
+extern RGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;
+extern RGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;
+extern RGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;
+extern RGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;
+extern RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;
+extern RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;
+extern RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;
+extern RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;
+extern RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;
+extern RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;
+
+struct rglgen_sym_map { const char *sym; void *ptr; };
+extern const struct rglgen_sym_map rglgen_symbol_map[];
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/deps/libretro-common/include/glsym/rglgen.h b/deps/libretro-common/include/glsym/rglgen.h
new file mode 100644 (file)
index 0000000..503223f
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsym).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 RGLGEN_H__
+#define RGLGEN_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <retro_common_api.h>
+
+#include "rglgen_headers.h"
+
+RETRO_BEGIN_DECLS
+
+struct rglgen_sym_map;
+
+typedef void (*rglgen_func_t)(void);
+typedef rglgen_func_t (*rglgen_proc_address_t)(const char*);
+void rglgen_resolve_symbols(rglgen_proc_address_t proc);
+void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
+      const struct rglgen_sym_map *map);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/glsym/rglgen_headers.h b/deps/libretro-common/include/glsym/rglgen_headers.h
new file mode 100644 (file)
index 0000000..7b44bef
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (glsym).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 RGLGEN_HEADERS_H__
+#define RGLGEN_HEADERS_H__
+
+#ifdef HAVE_EGL
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
+#include "rglgen_private_headers.h"
+
+#ifndef GL_MAP_WRITE_BIT
+#define GL_MAP_WRITE_BIT 0x0002
+#endif
+
+#ifndef GL_MAP_INVALIDATE_BUFFER_BIT
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#endif
+
+#ifndef GL_RED_INTEGER
+#define GL_RED_INTEGER 0x8D94
+#endif
+
+#ifndef GL_BGRA_EXT
+#define GL_BGRA_EXT GL_BGRA
+#endif
+
+#ifndef GL_LUMINANCE_ALPHA
+#define GL_LUMINANCE_ALPHA 0x190A
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/glsym/rglgen_private_headers.h b/deps/libretro-common/include/glsym/rglgen_private_headers.h
new file mode 100644 (file)
index 0000000..2b5e520
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 2010-2020 The RetroArch team\r
+ *\r
+ * ---------------------------------------------------------------------------------------\r
+ * The following license statement only applies to this libretro SDK code part (glsym).\r
+ * ---------------------------------------------------------------------------------------\r
+ *\r
+ * Permission is hereby granted, free of charge,\r
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\r
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+#ifndef RGLGEN_PRIVATE_HEADERS_H__\r
+#define RGLGEN_PRIVATE_HEADERS_H__\r
+\r
+#if defined(IOS)\r
+\r
+#if defined(HAVE_OPENGLES3)\r
+#include <OpenGLES/ES3/gl.h>\r
+#include <OpenGLES/ES3/glext.h>\r
+#else\r
+#include <OpenGLES/ES2/gl.h>\r
+#include <OpenGLES/ES2/glext.h>\r
+#endif\r
+\r
+#elif defined(__APPLE__)\r
+#include <compat/apple_compat.h>\r
+#if MAC_OS_X_VERSION_10_7\r
+#include <OpenGL/gl3.h>\r
+#include <OpenGL/gl3ext.h>\r
+#else\r
+#include <OpenGL/gl.h>\r
+#include <OpenGL/glext.h>\r
+#endif\r
+#elif defined(HAVE_PSGL)\r
+#include <PSGL/psgl.h>\r
+#include <GLES/glext.h>\r
+#elif defined(HAVE_OPENGL_MODERN)\r
+#include <GL3/gl3.h>\r
+#include <GL3/gl3ext.h>\r
+#elif defined(HAVE_OPENGLES3)\r
+#include <GLES3/gl3.h>\r
+#define __gl2_h_\r
+#include <GLES2/gl2ext.h>\r
+#elif defined(HAVE_OPENGLES2)\r
+#include <GLES2/gl2.h>\r
+#include <GLES2/gl2ext.h>\r
+#elif defined(HAVE_OPENGLES1)\r
+#include <GLES/gl.h>\r
+#include <GLES/glext.h>\r
+#else\r
+#if defined(_WIN32) && !defined(_XBOX)\r
+#define WIN32_LEAN_AND_MEAN\r
+#include <windows.h>\r
+#endif\r
+#ifndef HAVE_LIBNX\r
+#include <GL/gl.h>\r
+#include <GL/glext.h>\r
+#else\r
+/* We need to avoid including <GL/gl.h> on this platform */\r
+#include "switch/nx_gl.h"\r
+#include <GL/glext.h>\r
+#endif /* SWITCH */\r
+#endif\r
+\r
+#endif\r
diff --git a/deps/libretro-common/include/glsym/switch/nx_gl.h b/deps/libretro-common/include/glsym/switch/nx_gl.h
new file mode 100644 (file)
index 0000000..f4f37c0
--- /dev/null
@@ -0,0 +1,848 @@
+/* Copyright (C) 2018-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro SDK code part (nx_gl.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __NX_GL_H__
+#define __NX_GL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+// GL.h types
+typedef unsigned int   GLenum;
+typedef unsigned char  GLboolean;
+typedef unsigned int   GLbitfield;
+typedef void           GLvoid;
+typedef signed char    GLbyte;         /* 1-byte signed */
+typedef short          GLshort;        /* 2-byte signed */
+typedef int            GLint;          /* 4-byte signed */
+typedef unsigned char  GLubyte;        /* 1-byte unsigned */
+typedef unsigned short GLushort;       /* 2-byte unsigned */
+typedef unsigned int   GLuint;         /* 4-byte unsigned */
+typedef int            GLsizei;        /* 4-byte signed */
+typedef float          GLfloat;        /* single precision float */
+typedef float          GLclampf;       /* single precision float in [0,1] */
+typedef double         GLdouble;       /* double precision float */
+typedef double         GLclampd;       /* double precision float in [0,1] */
+
+// GL.h defines
+#define GL_ARB_imaging   1
+#define GL_FALSE                                0
+#define GL_TRUE                                 1
+#define GL_BYTE                                 0x1400
+#define GL_UNSIGNED_BYTE                        0x1401
+#define GL_SHORT                                0x1402
+#define GL_UNSIGNED_SHORT                       0x1403
+#define GL_INT                                  0x1404
+#define GL_UNSIGNED_INT                         0x1405
+#define GL_FLOAT                                0x1406
+#define GL_2_BYTES                              0x1407
+#define GL_3_BYTES                              0x1408
+#define GL_4_BYTES                              0x1409
+#define GL_DOUBLE                               0x140A
+#define GL_POINTS                               0x0000
+#define GL_LINES                                0x0001
+#define GL_LINE_LOOP                            0x0002
+#define GL_LINE_STRIP                           0x0003
+#define GL_TRIANGLES                            0x0004
+#define GL_TRIANGLE_STRIP                       0x0005
+#define GL_TRIANGLE_FAN                         0x0006
+#define GL_QUADS                                0x0007
+#define GL_QUAD_STRIP                           0x0008
+#define GL_POLYGON                              0x0009
+#define GL_VERTEX_ARRAY                         0x8074
+#define GL_NORMAL_ARRAY                         0x8075
+#define GL_COLOR_ARRAY                          0x8076
+#define GL_INDEX_ARRAY                          0x8077
+#define GL_TEXTURE_COORD_ARRAY                  0x8078
+#define GL_EDGE_FLAG_ARRAY                      0x8079
+#define GL_VERTEX_ARRAY_SIZE                    0x807A
+#define GL_VERTEX_ARRAY_TYPE                    0x807B
+#define GL_VERTEX_ARRAY_STRIDE                  0x807C
+#define GL_NORMAL_ARRAY_TYPE                    0x807E
+#define GL_NORMAL_ARRAY_STRIDE                  0x807F
+#define GL_COLOR_ARRAY_SIZE                     0x8081
+#define GL_COLOR_ARRAY_TYPE                     0x8082
+#define GL_COLOR_ARRAY_STRIDE                   0x8083
+#define GL_INDEX_ARRAY_TYPE                     0x8085
+#define GL_INDEX_ARRAY_STRIDE                   0x8086
+#define GL_TEXTURE_COORD_ARRAY_SIZE             0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE             0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE           0x808A
+#define GL_EDGE_FLAG_ARRAY_STRIDE               0x808C
+#define GL_VERTEX_ARRAY_POINTER                 0x808E
+#define GL_NORMAL_ARRAY_POINTER                 0x808F
+#define GL_COLOR_ARRAY_POINTER                  0x8090
+#define GL_INDEX_ARRAY_POINTER                  0x8091
+#define GL_TEXTURE_COORD_ARRAY_POINTER          0x8092
+#define GL_EDGE_FLAG_ARRAY_POINTER              0x8093
+#define GL_V2F                                  0x2A20
+#define GL_V3F                                  0x2A21
+#define GL_C4UB_V2F                             0x2A22
+#define GL_C4UB_V3F                             0x2A23
+#define GL_C3F_V3F                              0x2A24
+#define GL_N3F_V3F                              0x2A25
+#define GL_C4F_N3F_V3F                          0x2A26
+#define GL_T2F_V3F                              0x2A27
+#define GL_T4F_V4F                              0x2A28
+#define GL_T2F_C4UB_V3F                         0x2A29
+#define GL_T2F_C3F_V3F                          0x2A2A
+#define GL_T2F_N3F_V3F                          0x2A2B
+#define GL_T2F_C4F_N3F_V3F                      0x2A2C
+#define GL_T4F_C4F_N3F_V4F                      0x2A2D
+#define GL_MATRIX_MODE                          0x0BA0
+#define GL_MODELVIEW                            0x1700
+#define GL_PROJECTION                           0x1701
+#define GL_TEXTURE                              0x1702
+#define GL_POINT_SMOOTH                         0x0B10
+#define GL_POINT_SIZE                           0x0B11
+#define GL_POINT_SIZE_GRANULARITY               0x0B13
+#define GL_POINT_SIZE_RANGE                     0x0B12
+#define GL_LINE_SMOOTH                          0x0B20
+#define GL_LINE_STIPPLE                         0x0B24
+#define GL_LINE_STIPPLE_PATTERN                 0x0B25
+#define GL_LINE_STIPPLE_REPEAT                  0x0B26
+#define GL_LINE_WIDTH                           0x0B21
+#define GL_LINE_WIDTH_GRANULARITY               0x0B23
+#define GL_LINE_WIDTH_RANGE                     0x0B22
+#define GL_POINT                                0x1B00
+#define GL_LINE                                 0x1B01
+#define GL_FILL                                 0x1B02
+#define GL_CW                                   0x0900
+#define GL_CCW                                  0x0901
+#define GL_FRONT                                0x0404
+#define GL_BACK                                 0x0405
+#define GL_POLYGON_MODE                         0x0B40
+#define GL_POLYGON_SMOOTH                       0x0B41
+#define GL_POLYGON_STIPPLE                      0x0B42
+#define GL_EDGE_FLAG                            0x0B43
+#define GL_CULL_FACE                            0x0B44
+#define GL_CULL_FACE_MODE                       0x0B45
+#define GL_FRONT_FACE                           0x0B46
+#define GL_POLYGON_OFFSET_FACTOR                0x8038
+#define GL_POLYGON_OFFSET_UNITS                 0x2A00
+#define GL_POLYGON_OFFSET_POINT                 0x2A01
+#define GL_POLYGON_OFFSET_LINE                  0x2A02
+#define GL_POLYGON_OFFSET_FILL                  0x8037
+#define GL_COMPILE                              0x1300
+#define GL_COMPILE_AND_EXECUTE                  0x1301
+#define GL_LIST_BASE                            0x0B32
+#define GL_LIST_INDEX                           0x0B33
+#define GL_LIST_MODE                            0x0B30
+#define GL_NEVER                                0x0200
+#define GL_LESS                                 0x0201
+#define GL_EQUAL                                0x0202
+#define GL_LEQUAL                               0x0203
+#define GL_GREATER                              0x0204
+#define GL_NOTEQUAL                             0x0205
+#define GL_GEQUAL                               0x0206
+#define GL_ALWAYS                               0x0207
+#define GL_DEPTH_TEST                           0x0B71
+#define GL_DEPTH_BITS                           0x0D56
+#define GL_DEPTH_CLEAR_VALUE                    0x0B73
+#define GL_DEPTH_FUNC                           0x0B74
+#define GL_DEPTH_RANGE                          0x0B70
+#define GL_DEPTH_WRITEMASK                      0x0B72
+#define GL_DEPTH_COMPONENT                      0x1902
+#define GL_LIGHTING                             0x0B50
+#define GL_LIGHT0                               0x4000
+#define GL_LIGHT1                               0x4001
+#define GL_LIGHT2                               0x4002
+#define GL_LIGHT3                               0x4003
+#define GL_LIGHT4                               0x4004
+#define GL_LIGHT5                               0x4005
+#define GL_LIGHT6                               0x4006
+#define GL_LIGHT7                               0x4007
+#define GL_SPOT_EXPONENT                        0x1205
+#define GL_SPOT_CUTOFF                          0x1206
+#define GL_CONSTANT_ATTENUATION                 0x1207
+#define GL_LINEAR_ATTENUATION                   0x1208
+#define GL_QUADRATIC_ATTENUATION                0x1209
+#define GL_AMBIENT                              0x1200
+#define GL_DIFFUSE                              0x1201
+#define GL_SPECULAR                             0x1202
+#define GL_SHININESS                            0x1601
+#define GL_EMISSION                             0x1600
+#define GL_POSITION                             0x1203
+#define GL_SPOT_DIRECTION                       0x1204
+#define GL_AMBIENT_AND_DIFFUSE                  0x1602
+#define GL_COLOR_INDEXES                        0x1603
+#define GL_LIGHT_MODEL_TWO_SIDE                 0x0B52
+#define GL_LIGHT_MODEL_LOCAL_VIEWER             0x0B51
+#define GL_LIGHT_MODEL_AMBIENT                  0x0B53
+#define GL_FRONT_AND_BACK                       0x0408
+#define GL_SHADE_MODEL                          0x0B54
+#define GL_FLAT                                 0x1D00
+#define GL_SMOOTH                               0x1D01
+#define GL_COLOR_MATERIAL                       0x0B57
+#define GL_COLOR_MATERIAL_FACE                  0x0B55
+#define GL_COLOR_MATERIAL_PARAMETER             0x0B56
+#define GL_NORMALIZE                            0x0BA1
+#define GL_CLIP_PLANE0                          0x3000
+#define GL_CLIP_PLANE1                          0x3001
+#define GL_CLIP_PLANE2                          0x3002
+#define GL_CLIP_PLANE3                          0x3003
+#define GL_CLIP_PLANE4                          0x3004
+#define GL_CLIP_PLANE5                          0x3005
+#define GL_ACCUM_RED_BITS                       0x0D58
+#define GL_ACCUM_GREEN_BITS                     0x0D59
+#define GL_ACCUM_BLUE_BITS                      0x0D5A
+#define GL_ACCUM_ALPHA_BITS                     0x0D5B
+#define GL_ACCUM_CLEAR_VALUE                    0x0B80
+#define GL_ACCUM                                0x0100
+#define GL_ADD                                  0x0104
+#define GL_LOAD                                 0x0101
+#define GL_MULT                                 0x0103
+#define GL_RETURN                               0x0102
+#define GL_ALPHA_TEST                           0x0BC0
+#define GL_ALPHA_TEST_REF                       0x0BC2
+#define GL_ALPHA_TEST_FUNC                      0x0BC1
+#define GL_BLEND                                0x0BE2
+#define GL_BLEND_SRC                            0x0BE1
+#define GL_BLEND_DST                            0x0BE0
+#define GL_ZERO                                 0
+#define GL_ONE                                  1
+#define GL_SRC_COLOR                            0x0300
+#define GL_ONE_MINUS_SRC_COLOR                  0x0301
+#define GL_SRC_ALPHA                            0x0302
+#define GL_ONE_MINUS_SRC_ALPHA                  0x0303
+#define GL_DST_ALPHA                            0x0304
+#define GL_ONE_MINUS_DST_ALPHA                  0x0305
+#define GL_DST_COLOR                            0x0306
+#define GL_ONE_MINUS_DST_COLOR                  0x0307
+#define GL_SRC_ALPHA_SATURATE                   0x0308
+#define GL_FEEDBACK                             0x1C01
+#define GL_RENDER                               0x1C00
+#define GL_SELECT                               0x1C02
+#define GL_2D                                   0x0600
+#define GL_3D                                   0x0601
+#define GL_3D_COLOR                             0x0602
+#define GL_3D_COLOR_TEXTURE                     0x0603
+#define GL_4D_COLOR_TEXTURE                     0x0604
+#define GL_POINT_TOKEN                          0x0701
+#define GL_LINE_TOKEN                           0x0702
+#define GL_LINE_RESET_TOKEN                     0x0707
+#define GL_POLYGON_TOKEN                        0x0703
+#define GL_BITMAP_TOKEN                         0x0704
+#define GL_DRAW_PIXEL_TOKEN                     0x0705
+#define GL_COPY_PIXEL_TOKEN                     0x0706
+#define GL_PASS_THROUGH_TOKEN                   0x0700
+#define GL_FEEDBACK_BUFFER_POINTER              0x0DF0
+#define GL_FEEDBACK_BUFFER_SIZE                 0x0DF1
+#define GL_FEEDBACK_BUFFER_TYPE                 0x0DF2
+#define GL_SELECTION_BUFFER_POINTER             0x0DF3
+#define GL_SELECTION_BUFFER_SIZE                0x0DF4
+#define GL_FOG                                  0x0B60
+#define GL_FOG_MODE                             0x0B65
+#define GL_FOG_DENSITY                          0x0B62
+#define GL_FOG_COLOR                            0x0B66
+#define GL_FOG_INDEX                            0x0B61
+#define GL_FOG_START                            0x0B63
+#define GL_FOG_END                              0x0B64
+#define GL_LINEAR                               0x2601
+#define GL_EXP                                  0x0800
+#define GL_EXP2                                 0x0801
+#define GL_LOGIC_OP                             0x0BF1
+#define GL_INDEX_LOGIC_OP                       0x0BF1
+#define GL_COLOR_LOGIC_OP                       0x0BF2
+#define GL_LOGIC_OP_MODE                        0x0BF0
+#define GL_CLEAR                                0x1500
+#define GL_SET                                  0x150F
+#define GL_COPY                                 0x1503
+#define GL_COPY_INVERTED                        0x150C
+#define GL_NOOP                                 0x1505
+#define GL_INVERT                               0x150A
+#define GL_AND                                  0x1501
+#define GL_NAND                                 0x150E
+#define GL_OR                                   0x1507
+#define GL_NOR                                  0x1508
+#define GL_XOR                                  0x1506
+#define GL_EQUIV                                0x1509
+#define GL_AND_REVERSE                          0x1502
+#define GL_AND_INVERTED                         0x1504
+#define GL_OR_REVERSE                           0x150B
+#define GL_OR_INVERTED                          0x150D
+#define GL_STENCIL_BITS                         0x0D57
+#define GL_STENCIL_TEST                         0x0B90
+#define GL_STENCIL_CLEAR_VALUE                  0x0B91
+#define GL_STENCIL_FUNC                         0x0B92
+#define GL_STENCIL_VALUE_MASK                   0x0B93
+#define GL_STENCIL_FAIL                         0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL              0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS              0x0B96
+#define GL_STENCIL_REF                          0x0B97
+#define GL_STENCIL_WRITEMASK                    0x0B98
+#define GL_STENCIL_INDEX                        0x1901
+#define GL_KEEP                                 0x1E00
+#define GL_REPLACE                              0x1E01
+#define GL_INCR                                 0x1E02
+#define GL_DECR                                 0x1E03
+#define GL_NONE                                 0
+#define GL_LEFT                                 0x0406
+#define GL_RIGHT                                0x0407
+#define GL_FRONT_LEFT                           0x0400
+#define GL_FRONT_RIGHT                          0x0401
+#define GL_BACK_LEFT                            0x0402
+#define GL_BACK_RIGHT                           0x0403
+#define GL_AUX0                                 0x0409
+#define GL_AUX1                                 0x040A
+#define GL_AUX2                                 0x040B
+#define GL_AUX3                                 0x040C
+#define GL_COLOR_INDEX                          0x1900
+#define GL_RED                                  0x1903
+#define GL_GREEN                                0x1904
+#define GL_BLUE                                 0x1905
+#define GL_ALPHA                                0x1906
+#define GL_LUMINANCE                            0x1909
+#define GL_LUMINANCE_ALPHA                      0x190A
+#define GL_ALPHA_BITS                           0x0D55
+#define GL_RED_BITS                             0x0D52
+#define GL_GREEN_BITS                           0x0D53
+#define GL_BLUE_BITS                            0x0D54
+#define GL_INDEX_BITS                           0x0D51
+#define GL_SUBPIXEL_BITS                        0x0D50
+#define GL_AUX_BUFFERS                          0x0C00
+#define GL_READ_BUFFER                          0x0C02
+#define GL_DRAW_BUFFER                          0x0C01
+#define GL_DOUBLEBUFFER                         0x0C32
+#define GL_STEREO                               0x0C33
+#define GL_BITMAP                               0x1A00
+#define GL_COLOR                                0x1800
+#define GL_DEPTH                                0x1801
+#define GL_STENCIL                              0x1802
+#define GL_DITHER                               0x0BD0
+#define GL_RGB                                  0x1907
+#define GL_RGBA                                 0x1908
+#define GL_MAX_LIST_NESTING                     0x0B31
+#define GL_MAX_EVAL_ORDER                       0x0D30
+#define GL_MAX_LIGHTS                           0x0D31
+#define GL_MAX_CLIP_PLANES                      0x0D32
+#define GL_MAX_TEXTURE_SIZE                     0x0D33
+#define GL_MAX_PIXEL_MAP_TABLE                  0x0D34
+#define GL_MAX_ATTRIB_STACK_DEPTH               0x0D35
+#define GL_MAX_MODELVIEW_STACK_DEPTH            0x0D36
+#define GL_MAX_NAME_STACK_DEPTH                 0x0D37
+#define GL_MAX_PROJECTION_STACK_DEPTH           0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH              0x0D39
+#define GL_MAX_VIEWPORT_DIMS                    0x0D3A
+#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH        0x0D3B
+#define GL_ATTRIB_STACK_DEPTH                   0x0BB0
+#define GL_CLIENT_ATTRIB_STACK_DEPTH            0x0BB1
+#define GL_COLOR_CLEAR_VALUE                    0x0C22
+#define GL_COLOR_WRITEMASK                      0x0C23
+#define GL_CURRENT_INDEX                        0x0B01
+#define GL_CURRENT_COLOR                        0x0B00
+#define GL_CURRENT_NORMAL                       0x0B02
+#define GL_CURRENT_RASTER_COLOR                 0x0B04
+#define GL_CURRENT_RASTER_DISTANCE              0x0B09
+#define GL_CURRENT_RASTER_INDEX                 0x0B05
+#define GL_CURRENT_RASTER_POSITION              0x0B07
+#define GL_CURRENT_RASTER_TEXTURE_COORDS        0x0B06
+#define GL_CURRENT_RASTER_POSITION_VALID        0x0B08
+#define GL_CURRENT_TEXTURE_COORDS               0x0B03
+#define GL_INDEX_CLEAR_VALUE                    0x0C20
+#define GL_INDEX_MODE                           0x0C30
+#define GL_INDEX_WRITEMASK                      0x0C21
+#define GL_MODELVIEW_MATRIX                     0x0BA6
+#define GL_MODELVIEW_STACK_DEPTH                0x0BA3
+#define GL_NAME_STACK_DEPTH                     0x0D70
+#define GL_PROJECTION_MATRIX                    0x0BA7
+#define GL_PROJECTION_STACK_DEPTH               0x0BA4
+#define GL_RENDER_MODE                          0x0C40
+#define GL_RGBA_MODE                            0x0C31
+#define GL_TEXTURE_MATRIX                       0x0BA8
+#define GL_TEXTURE_STACK_DEPTH                  0x0BA5
+#define GL_VIEWPORT                             0x0BA2
+#define GL_AUTO_NORMAL                          0x0D80
+#define GL_MAP1_COLOR_4                         0x0D90
+#define GL_MAP1_INDEX                           0x0D91
+#define GL_MAP1_NORMAL                          0x0D92
+#define GL_MAP1_TEXTURE_COORD_1                 0x0D93
+#define GL_MAP1_TEXTURE_COORD_2                 0x0D94
+#define GL_MAP1_TEXTURE_COORD_3                 0x0D95
+#define GL_MAP1_TEXTURE_COORD_4                 0x0D96
+#define GL_MAP1_VERTEX_3                        0x0D97
+#define GL_MAP1_VERTEX_4                        0x0D98
+#define GL_MAP2_COLOR_4                         0x0DB0
+#define GL_MAP2_INDEX                           0x0DB1
+#define GL_MAP2_NORMAL                          0x0DB2
+#define GL_MAP2_TEXTURE_COORD_1                 0x0DB3
+#define GL_MAP2_TEXTURE_COORD_2                 0x0DB4
+#define GL_MAP2_TEXTURE_COORD_3                 0x0DB5
+#define GL_MAP2_TEXTURE_COORD_4                 0x0DB6
+#define GL_MAP2_VERTEX_3                        0x0DB7
+#define GL_MAP2_VERTEX_4                        0x0DB8
+#define GL_MAP1_GRID_DOMAIN                     0x0DD0
+#define GL_MAP1_GRID_SEGMENTS                   0x0DD1
+#define GL_MAP2_GRID_DOMAIN                     0x0DD2
+#define GL_MAP2_GRID_SEGMENTS                   0x0DD3
+#define GL_COEFF                                0x0A00
+#define GL_ORDER                                0x0A01
+#define GL_DOMAIN                               0x0A02
+#define GL_PERSPECTIVE_CORRECTION_HINT          0x0C50
+#define GL_POINT_SMOOTH_HINT                    0x0C51
+#define GL_LINE_SMOOTH_HINT                     0x0C52
+#define GL_POLYGON_SMOOTH_HINT                  0x0C53
+#define GL_FOG_HINT                             0x0C54
+#define GL_DONT_CARE                            0x1100
+#define GL_FASTEST                              0x1101
+#define GL_NICEST                               0x1102
+#define GL_SCISSOR_BOX                          0x0C10
+#define GL_SCISSOR_TEST                         0x0C11
+#define GL_MAP_COLOR                            0x0D10
+#define GL_MAP_STENCIL                          0x0D11
+#define GL_INDEX_SHIFT                          0x0D12
+#define GL_INDEX_OFFSET                         0x0D13
+#define GL_RED_SCALE                            0x0D14
+#define GL_RED_BIAS                             0x0D15
+#define GL_GREEN_SCALE                          0x0D18
+#define GL_GREEN_BIAS                           0x0D19
+#define GL_BLUE_SCALE                           0x0D1A
+#define GL_BLUE_BIAS                            0x0D1B
+#define GL_ALPHA_SCALE                          0x0D1C
+#define GL_ALPHA_BIAS                           0x0D1D
+#define GL_DEPTH_SCALE                          0x0D1E
+#define GL_DEPTH_BIAS                           0x0D1F
+#define GL_PIXEL_MAP_S_TO_S_SIZE                0x0CB1
+#define GL_PIXEL_MAP_I_TO_I_SIZE                0x0CB0
+#define GL_PIXEL_MAP_I_TO_R_SIZE                0x0CB2
+#define GL_PIXEL_MAP_I_TO_G_SIZE                0x0CB3
+#define GL_PIXEL_MAP_I_TO_B_SIZE                0x0CB4
+#define GL_PIXEL_MAP_I_TO_A_SIZE                0x0CB5
+#define GL_PIXEL_MAP_R_TO_R_SIZE                0x0CB6
+#define GL_PIXEL_MAP_G_TO_G_SIZE                0x0CB7
+#define GL_PIXEL_MAP_B_TO_B_SIZE                0x0CB8
+#define GL_PIXEL_MAP_A_TO_A_SIZE                0x0CB9
+#define GL_PIXEL_MAP_S_TO_S                     0x0C71
+#define GL_PIXEL_MAP_I_TO_I                     0x0C70
+#define GL_PIXEL_MAP_I_TO_R                     0x0C72
+#define GL_PIXEL_MAP_I_TO_G                     0x0C73
+#define GL_PIXEL_MAP_I_TO_B                     0x0C74
+#define GL_PIXEL_MAP_I_TO_A                     0x0C75
+#define GL_PIXEL_MAP_R_TO_R                     0x0C76
+#define GL_PIXEL_MAP_G_TO_G                     0x0C77
+#define GL_PIXEL_MAP_B_TO_B                     0x0C78
+#define GL_PIXEL_MAP_A_TO_A                     0x0C79
+#define GL_PACK_ALIGNMENT                       0x0D05
+#define GL_PACK_LSB_FIRST                       0x0D01
+#define GL_PACK_ROW_LENGTH                      0x0D02
+#define GL_PACK_SKIP_PIXELS                     0x0D04
+#define GL_PACK_SKIP_ROWS                       0x0D03
+#define GL_PACK_SWAP_BYTES                      0x0D00
+#define GL_UNPACK_ALIGNMENT                     0x0CF5
+#define GL_UNPACK_LSB_FIRST                     0x0CF1
+#define GL_UNPACK_ROW_LENGTH                    0x0CF2
+#define GL_UNPACK_SKIP_PIXELS                   0x0CF4
+#define GL_UNPACK_SKIP_ROWS                     0x0CF3
+#define GL_UNPACK_SWAP_BYTES                    0x0CF0
+#define GL_ZOOM_X                               0x0D16
+#define GL_ZOOM_Y                               0x0D17
+#define GL_TEXTURE_ENV                          0x2300
+#define GL_TEXTURE_ENV_MODE                     0x2200
+#define GL_TEXTURE_1D                           0x0DE0
+#define GL_TEXTURE_2D                           0x0DE1
+#define GL_TEXTURE_WRAP_S                       0x2802
+#define GL_TEXTURE_WRAP_T                       0x2803
+#define GL_TEXTURE_MAG_FILTER                   0x2800
+#define GL_TEXTURE_MIN_FILTER                   0x2801
+#define GL_TEXTURE_ENV_COLOR                    0x2201
+#define GL_TEXTURE_GEN_S                        0x0C60
+#define GL_TEXTURE_GEN_T                        0x0C61
+#define GL_TEXTURE_GEN_R                        0x0C62
+#define GL_TEXTURE_GEN_Q                        0x0C63
+#define GL_TEXTURE_GEN_MODE                     0x2500
+#define GL_TEXTURE_BORDER_COLOR                 0x1004
+#define GL_TEXTURE_WIDTH                        0x1000
+#define GL_TEXTURE_HEIGHT                       0x1001
+#define GL_TEXTURE_BORDER                       0x1005
+#define GL_TEXTURE_COMPONENTS                   0x1003
+#define GL_TEXTURE_RED_SIZE                     0x805C
+#define GL_TEXTURE_GREEN_SIZE                   0x805D
+#define GL_TEXTURE_BLUE_SIZE                    0x805E
+#define GL_TEXTURE_ALPHA_SIZE                   0x805F
+#define GL_TEXTURE_LUMINANCE_SIZE               0x8060
+#define GL_TEXTURE_INTENSITY_SIZE               0x8061
+#define GL_NEAREST_MIPMAP_NEAREST               0x2700
+#define GL_NEAREST_MIPMAP_LINEAR                0x2702
+#define GL_LINEAR_MIPMAP_NEAREST                0x2701
+#define GL_LINEAR_MIPMAP_LINEAR                 0x2703
+#define GL_OBJECT_LINEAR                        0x2401
+#define GL_OBJECT_PLANE                         0x2501
+#define GL_EYE_LINEAR                           0x2400
+#define GL_EYE_PLANE                            0x2502
+#define GL_SPHERE_MAP                           0x2402
+#define GL_DECAL                                0x2101
+#define GL_MODULATE                             0x2100
+#define GL_NEAREST                              0x2600
+#define GL_REPEAT                               0x2901
+#define GL_CLAMP                                0x2900
+#define GL_S                                    0x2000
+#define GL_T                                    0x2001
+#define GL_R                                    0x2002
+#define GL_Q                                    0x2003
+#define GL_VENDOR                               0x1F00
+#define GL_RENDERER                             0x1F01
+#define GL_VERSION                              0x1F02
+#define GL_EXTENSIONS                           0x1F03
+#define GL_NO_ERROR                             0
+#define GL_INVALID_ENUM                         0x0500
+#define GL_INVALID_VALUE                        0x0501
+#define GL_INVALID_OPERATION                    0x0502
+#define GL_STACK_OVERFLOW                       0x0503
+#define GL_STACK_UNDERFLOW                      0x0504
+#define GL_OUT_OF_MEMORY                        0x0505
+#define GL_CURRENT_BIT                          0x00000001
+#define GL_POINT_BIT                            0x00000002
+#define GL_LINE_BIT                             0x00000004
+#define GL_POLYGON_BIT                          0x00000008
+#define GL_POLYGON_STIPPLE_BIT                  0x00000010
+#define GL_PIXEL_MODE_BIT                       0x00000020
+#define GL_LIGHTING_BIT                         0x00000040
+#define GL_FOG_BIT                              0x00000080
+#define GL_DEPTH_BUFFER_BIT                     0x00000100
+#define GL_ACCUM_BUFFER_BIT                     0x00000200
+#define GL_STENCIL_BUFFER_BIT                   0x00000400
+#define GL_VIEWPORT_BIT                         0x00000800
+#define GL_TRANSFORM_BIT                        0x00001000
+#define GL_ENABLE_BIT                           0x00002000
+#define GL_COLOR_BUFFER_BIT                     0x00004000
+#define GL_HINT_BIT                             0x00008000
+#define GL_EVAL_BIT                             0x00010000
+#define GL_LIST_BIT                             0x00020000
+#define GL_TEXTURE_BIT                          0x00040000
+#define GL_SCISSOR_BIT                          0x00080000
+#define GL_ALL_ATTRIB_BITS                      0xFFFFFFFF
+#define GL_PROXY_TEXTURE_1D                     0x8063
+#define GL_PROXY_TEXTURE_2D                     0x8064
+#define GL_TEXTURE_PRIORITY                     0x8066
+#define GL_TEXTURE_RESIDENT                     0x8067
+#define GL_TEXTURE_BINDING_1D                   0x8068
+#define GL_TEXTURE_BINDING_2D                   0x8069
+#define GL_TEXTURE_INTERNAL_FORMAT              0x1003
+#define GL_ALPHA4                               0x803B
+#define GL_ALPHA8                               0x803C
+#define GL_ALPHA12                              0x803D
+#define GL_ALPHA16                              0x803E
+#define GL_LUMINANCE4                           0x803F
+#define GL_LUMINANCE8                           0x8040
+#define GL_LUMINANCE12                          0x8041
+#define GL_LUMINANCE16                          0x8042
+#define GL_LUMINANCE4_ALPHA4                    0x8043
+#define GL_LUMINANCE6_ALPHA2                    0x8044
+#define GL_LUMINANCE8_ALPHA8                    0x8045
+#define GL_LUMINANCE12_ALPHA4                   0x8046
+#define GL_LUMINANCE12_ALPHA12                  0x8047
+#define GL_LUMINANCE16_ALPHA16                  0x8048
+#define GL_INTENSITY                            0x8049
+#define GL_INTENSITY4                           0x804A
+#define GL_INTENSITY8                           0x804B
+#define GL_INTENSITY12                          0x804C
+#define GL_INTENSITY16                          0x804D
+#define GL_R3_G3_B2                             0x2A10
+#define GL_RGB4                                 0x804F
+#define GL_RGB5                                 0x8050
+#define GL_RGB8                                 0x8051
+#define GL_RGB10                                0x8052
+#define GL_RGB12                                0x8053
+#define GL_RGB16                                0x8054
+#define GL_RGBA2                                0x8055
+#define GL_RGBA4                                0x8056
+#define GL_RGB5_A1                              0x8057
+#define GL_RGBA8                                0x8058
+#define GL_RGB10_A2                             0x8059
+#define GL_RGBA12                               0x805A
+#define GL_RGBA16                               0x805B
+#define GL_CLIENT_PIXEL_STORE_BIT               0x00000001
+#define GL_CLIENT_VERTEX_ARRAY_BIT              0x00000002
+#define GL_ALL_CLIENT_ATTRIB_BITS               0xFFFFFFFF
+#define GL_CLIENT_ALL_ATTRIB_BITS               0xFFFFFFFF
+#define GL_RESCALE_NORMAL                       0x803A
+#define GL_CLAMP_TO_EDGE                        0x812F
+#define GL_MAX_ELEMENTS_VERTICES                0x80E8
+#define GL_MAX_ELEMENTS_INDICES                 0x80E9
+#define GL_BGR                                  0x80E0
+#define GL_BGRA                                 0x80E1
+#define GL_UNSIGNED_BYTE_3_3_2                  0x8032
+#define GL_UNSIGNED_BYTE_2_3_3_REV              0x8362
+#define GL_UNSIGNED_SHORT_5_6_5                 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV             0x8364
+#define GL_UNSIGNED_SHORT_4_4_4_4               0x8033
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV           0x8365
+#define GL_UNSIGNED_SHORT_5_5_5_1               0x8034
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV           0x8366
+#define GL_UNSIGNED_INT_8_8_8_8                 0x8035
+#define GL_UNSIGNED_INT_8_8_8_8_REV             0x8367
+#define GL_UNSIGNED_INT_10_10_10_2              0x8036
+#define GL_UNSIGNED_INT_2_10_10_10_REV          0x8368
+#define GL_LIGHT_MODEL_COLOR_CONTROL            0x81F8
+#define GL_SINGLE_COLOR                         0x81F9
+#define GL_SEPARATE_SPECULAR_COLOR              0x81FA
+#define GL_TEXTURE_MIN_LOD                      0x813A
+#define GL_TEXTURE_MAX_LOD                      0x813B
+#define GL_TEXTURE_BASE_LEVEL                   0x813C
+#define GL_TEXTURE_MAX_LEVEL                    0x813D
+#define GL_SMOOTH_POINT_SIZE_RANGE              0x0B12
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY        0x0B13
+#define GL_SMOOTH_LINE_WIDTH_RANGE              0x0B22
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY        0x0B23
+#define GL_ALIASED_POINT_SIZE_RANGE             0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE             0x846E
+#define GL_PACK_SKIP_IMAGES                     0x806B
+#define GL_PACK_IMAGE_HEIGHT                    0x806C
+#define GL_UNPACK_SKIP_IMAGES                   0x806D
+#define GL_UNPACK_IMAGE_HEIGHT                  0x806E
+#define GL_TEXTURE_3D                           0x806F
+#define GL_PROXY_TEXTURE_3D                     0x8070
+#define GL_TEXTURE_DEPTH                        0x8071
+#define GL_TEXTURE_WRAP_R                       0x8072
+#define GL_MAX_3D_TEXTURE_SIZE                  0x8073
+#define GL_TEXTURE_BINDING_3D                   0x806A
+#define GL_CONSTANT_COLOR                       0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR             0x8002
+#define GL_CONSTANT_ALPHA                       0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA             0x8004
+#define GL_COLOR_TABLE                          0x80D0
+#define GL_POST_CONVOLUTION_COLOR_TABLE         0x80D1
+#define GL_POST_COLOR_MATRIX_COLOR_TABLE        0x80D2
+#define GL_PROXY_COLOR_TABLE                    0x80D3
+#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE   0x80D4
+#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE  0x80D5
+#define GL_COLOR_TABLE_SCALE                    0x80D6
+#define GL_COLOR_TABLE_BIAS                     0x80D7
+#define GL_COLOR_TABLE_FORMAT                   0x80D8
+#define GL_COLOR_TABLE_WIDTH                    0x80D9
+#define GL_COLOR_TABLE_RED_SIZE                 0x80DA
+#define GL_COLOR_TABLE_GREEN_SIZE               0x80DB
+#define GL_COLOR_TABLE_BLUE_SIZE                0x80DC
+#define GL_COLOR_TABLE_ALPHA_SIZE               0x80DD
+#define GL_COLOR_TABLE_LUMINANCE_SIZE           0x80DE
+#define GL_COLOR_TABLE_INTENSITY_SIZE           0x80DF
+#define GL_CONVOLUTION_1D                       0x8010
+#define GL_CONVOLUTION_2D                       0x8011
+#define GL_SEPARABLE_2D                         0x8012
+#define GL_CONVOLUTION_BORDER_MODE              0x8013
+#define GL_CONVOLUTION_FILTER_SCALE             0x8014
+#define GL_CONVOLUTION_FILTER_BIAS              0x8015
+#define GL_REDUCE                               0x8016
+#define GL_CONVOLUTION_FORMAT                   0x8017
+#define GL_CONVOLUTION_WIDTH                    0x8018
+#define GL_CONVOLUTION_HEIGHT                   0x8019
+#define GL_MAX_CONVOLUTION_WIDTH                0x801A
+#define GL_MAX_CONVOLUTION_HEIGHT               0x801B
+#define GL_POST_CONVOLUTION_RED_SCALE           0x801C
+#define GL_POST_CONVOLUTION_GREEN_SCALE         0x801D
+#define GL_POST_CONVOLUTION_BLUE_SCALE          0x801E
+#define GL_POST_CONVOLUTION_ALPHA_SCALE         0x801F
+#define GL_POST_CONVOLUTION_RED_BIAS            0x8020
+#define GL_POST_CONVOLUTION_GREEN_BIAS          0x8021
+#define GL_POST_CONVOLUTION_BLUE_BIAS           0x8022
+#define GL_POST_CONVOLUTION_ALPHA_BIAS          0x8023
+#define GL_CONSTANT_BORDER                      0x8151
+#define GL_REPLICATE_BORDER                     0x8153
+#define GL_CONVOLUTION_BORDER_COLOR             0x8154
+#define GL_COLOR_MATRIX                         0x80B1
+#define GL_COLOR_MATRIX_STACK_DEPTH             0x80B2
+#define GL_MAX_COLOR_MATRIX_STACK_DEPTH         0x80B3
+#define GL_POST_COLOR_MATRIX_RED_SCALE          0x80B4
+#define GL_POST_COLOR_MATRIX_GREEN_SCALE        0x80B5
+#define GL_POST_COLOR_MATRIX_BLUE_SCALE         0x80B6
+#define GL_POST_COLOR_MATRIX_ALPHA_SCALE        0x80B7
+#define GL_POST_COLOR_MATRIX_RED_BIAS           0x80B8
+#define GL_POST_COLOR_MATRIX_GREEN_BIAS         0x80B9
+#define GL_POST_COLOR_MATRIX_BLUE_BIAS          0x80BA
+#define GL_POST_COLOR_MATRIX_ALPHA_BIAS         0x80BB
+#define GL_HISTOGRAM                            0x8024
+#define GL_PROXY_HISTOGRAM                      0x8025
+#define GL_HISTOGRAM_WIDTH                      0x8026
+#define GL_HISTOGRAM_FORMAT                     0x8027
+#define GL_HISTOGRAM_RED_SIZE                   0x8028
+#define GL_HISTOGRAM_GREEN_SIZE                 0x8029
+#define GL_HISTOGRAM_BLUE_SIZE                  0x802A
+#define GL_HISTOGRAM_ALPHA_SIZE                 0x802B
+#define GL_HISTOGRAM_LUMINANCE_SIZE             0x802C
+#define GL_HISTOGRAM_SINK                       0x802D
+#define GL_MINMAX                               0x802E
+#define GL_MINMAX_FORMAT                        0x802F
+#define GL_MINMAX_SINK                          0x8030
+#define GL_TABLE_TOO_LARGE                      0x8031
+#define GL_BLEND_EQUATION                       0x8009
+#define GL_MIN                                  0x8007
+#define GL_MAX                                  0x8008
+#define GL_FUNC_ADD                             0x8006
+#define GL_FUNC_SUBTRACT                        0x800A
+#define GL_FUNC_REVERSE_SUBTRACT                0x800B
+#define GL_BLEND_COLOR                          0x8005
+#define GL_TEXTURE0                             0x84C0
+#define GL_TEXTURE1                             0x84C1
+#define GL_TEXTURE2                             0x84C2
+#define GL_TEXTURE3                             0x84C3
+#define GL_TEXTURE4                             0x84C4
+#define GL_TEXTURE5                             0x84C5
+#define GL_TEXTURE6                             0x84C6
+#define GL_TEXTURE7                             0x84C7
+#define GL_TEXTURE8                             0x84C8
+#define GL_TEXTURE9                             0x84C9
+#define GL_TEXTURE10                            0x84CA
+#define GL_TEXTURE11                            0x84CB
+#define GL_TEXTURE12                            0x84CC
+#define GL_TEXTURE13                            0x84CD
+#define GL_TEXTURE14                            0x84CE
+#define GL_TEXTURE15                            0x84CF
+#define GL_TEXTURE16                            0x84D0
+#define GL_TEXTURE17                            0x84D1
+#define GL_TEXTURE18                            0x84D2
+#define GL_TEXTURE19                            0x84D3
+#define GL_TEXTURE20                            0x84D4
+#define GL_TEXTURE21                            0x84D5
+#define GL_TEXTURE22                            0x84D6
+#define GL_TEXTURE23                            0x84D7
+#define GL_TEXTURE24                            0x84D8
+#define GL_TEXTURE25                            0x84D9
+#define GL_TEXTURE26                            0x84DA
+#define GL_TEXTURE27                            0x84DB
+#define GL_TEXTURE28                            0x84DC
+#define GL_TEXTURE29                            0x84DD
+#define GL_TEXTURE30                            0x84DE
+#define GL_TEXTURE31                            0x84DF
+#define GL_ACTIVE_TEXTURE                       0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE                0x84E1
+#define GL_MAX_TEXTURE_UNITS                    0x84E2
+#define GL_NORMAL_MAP                           0x8511
+#define GL_REFLECTION_MAP                       0x8512
+#define GL_TEXTURE_CUBE_MAP                     0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP             0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X          0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X          0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y          0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y          0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z          0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z          0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP               0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE            0x851C
+#define GL_COMPRESSED_ALPHA                     0x84E9
+#define GL_COMPRESSED_LUMINANCE                 0x84EA
+#define GL_COMPRESSED_LUMINANCE_ALPHA           0x84EB
+#define GL_COMPRESSED_INTENSITY                 0x84EC
+#define GL_COMPRESSED_RGB                       0x84ED
+#define GL_COMPRESSED_RGBA                      0x84EE
+#define GL_TEXTURE_COMPRESSION_HINT             0x84EF
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE        0x86A0
+#define GL_TEXTURE_COMPRESSED                   0x86A1
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS       0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS           0x86A3
+#define GL_MULTISAMPLE                          0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE             0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE                  0x809F
+#define GL_SAMPLE_COVERAGE                      0x80A0
+#define GL_SAMPLE_BUFFERS                       0x80A8
+#define GL_SAMPLES                              0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE                0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT               0x80AB
+#define GL_MULTISAMPLE_BIT                      0x20000000
+#define GL_TRANSPOSE_MODELVIEW_MATRIX           0x84E3
+#define GL_TRANSPOSE_PROJECTION_MATRIX          0x84E4
+#define GL_TRANSPOSE_TEXTURE_MATRIX             0x84E5
+#define GL_TRANSPOSE_COLOR_MATRIX               0x84E6
+#define GL_COMBINE                              0x8570
+#define GL_COMBINE_RGB                          0x8571
+#define GL_COMBINE_ALPHA                        0x8572
+#define GL_SOURCE0_RGB                          0x8580
+#define GL_SOURCE1_RGB                          0x8581
+#define GL_SOURCE2_RGB                          0x8582
+#define GL_SOURCE0_ALPHA                        0x8588
+#define GL_SOURCE1_ALPHA                        0x8589
+#define GL_SOURCE2_ALPHA                        0x858A
+#define GL_OPERAND0_RGB                         0x8590
+#define GL_OPERAND1_RGB                         0x8591
+#define GL_OPERAND2_RGB                         0x8592
+#define GL_OPERAND0_ALPHA                       0x8598
+#define GL_OPERAND1_ALPHA                       0x8599
+#define GL_OPERAND2_ALPHA                       0x859A
+#define GL_RGB_SCALE                            0x8573
+#define GL_ADD_SIGNED                           0x8574
+#define GL_INTERPOLATE                          0x8575
+#define GL_SUBTRACT                             0x84E7
+#define GL_CONSTANT                             0x8576
+#define GL_PRIMARY_COLOR                        0x8577
+#define GL_PREVIOUS                             0x8578
+#define GL_DOT3_RGB                             0x86AE
+#define GL_DOT3_RGBA                            0x86AF
+#define GL_CLAMP_TO_BORDER                      0x812D
+#define GL_ARB_multitexture 1
+#define GL_TEXTURE0_ARB                         0x84C0
+#define GL_TEXTURE1_ARB                         0x84C1
+#define GL_TEXTURE2_ARB                         0x84C2
+#define GL_TEXTURE3_ARB                         0x84C3
+#define GL_TEXTURE4_ARB                         0x84C4
+#define GL_TEXTURE5_ARB                         0x84C5
+#define GL_TEXTURE6_ARB                         0x84C6
+#define GL_TEXTURE7_ARB                         0x84C7
+#define GL_TEXTURE8_ARB                         0x84C8
+#define GL_TEXTURE9_ARB                         0x84C9
+#define GL_TEXTURE10_ARB                        0x84CA
+#define GL_TEXTURE11_ARB                        0x84CB
+#define GL_TEXTURE12_ARB                        0x84CC
+#define GL_TEXTURE13_ARB                        0x84CD
+#define GL_TEXTURE14_ARB                        0x84CE
+#define GL_TEXTURE15_ARB                        0x84CF
+#define GL_TEXTURE16_ARB                        0x84D0
+#define GL_TEXTURE17_ARB                        0x84D1
+#define GL_TEXTURE18_ARB                        0x84D2
+#define GL_TEXTURE19_ARB                        0x84D3
+#define GL_TEXTURE20_ARB                        0x84D4
+#define GL_TEXTURE21_ARB                        0x84D5
+#define GL_TEXTURE22_ARB                        0x84D6
+#define GL_TEXTURE23_ARB                        0x84D7
+#define GL_TEXTURE24_ARB                        0x84D8
+#define GL_TEXTURE25_ARB                        0x84D9
+#define GL_TEXTURE26_ARB                        0x84DA
+#define GL_TEXTURE27_ARB                        0x84DB
+#define GL_TEXTURE28_ARB                        0x84DC
+#define GL_TEXTURE29_ARB                        0x84DD
+#define GL_TEXTURE30_ARB                        0x84DE
+#define GL_TEXTURE31_ARB                        0x84DF
+#define GL_ACTIVE_TEXTURE_ARB                   0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE_ARB            0x84E1
+#define GL_MAX_TEXTURE_UNITS_ARB                0x84E2
+#define GL_MESA_packed_depth_stencil 1
+#define GL_DEPTH_STENCIL_MESA                   0x8750
+#define GL_UNSIGNED_INT_24_8_MESA               0x8751
+#define GL_UNSIGNED_INT_8_24_REV_MESA           0x8752
+#define GL_UNSIGNED_SHORT_15_1_MESA             0x8753
+#define GL_UNSIGNED_SHORT_1_15_REV_MESA         0x8754
+#define GL_ATI_blend_equation_separate 1
+#define GL_ALPHA_BLEND_EQUATION_ATI             0x883D
+#define GL_OES_EGL_image 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __NX_GL_H__
diff --git a/deps/libretro-common/include/glsym/switch/nx_glsym.h b/deps/libretro-common/include/glsym/switch/nx_glsym.h
new file mode 100644 (file)
index 0000000..ce11223
--- /dev/null
@@ -0,0 +1,928 @@
+#ifndef __NX_GLSYM_H__
+#define __NX_GLSYM_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *GLeglImageOES;
+typedef void (APIENTRYP RGLSYMGLCLEARINDEXPROC) ( GLfloat c );
+typedef void (APIENTRYP RGLSYMGLCLEARCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
+typedef void (APIENTRYP RGLSYMGLCLEARPROC) ( GLbitfield mask );
+typedef void (APIENTRYP RGLSYMGLINDEXMASKPROC) ( GLuint mask );
+typedef void (APIENTRYP RGLSYMGLCOLORMASKPROC) ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha );
+typedef void (APIENTRYP RGLSYMGLALPHAFUNCPROC) ( GLenum func, GLclampf ref );
+typedef void (APIENTRYP RGLSYMGLBLENDFUNCPROC) ( GLenum sfactor, GLenum dfactor );
+typedef void (APIENTRYP RGLSYMGLLOGICOPPROC) ( GLenum opcode );
+typedef void (APIENTRYP RGLSYMGLCULLFACEPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLFRONTFACEPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLPOINTSIZEPROC) ( GLfloat size );
+typedef void (APIENTRYP RGLSYMGLLINEWIDTHPROC) ( GLfloat width );
+typedef void (APIENTRYP RGLSYMGLLINESTIPPLEPROC) ( GLint factor, GLushort pattern );
+typedef void (APIENTRYP RGLSYMGLPOLYGONMODEPROC) ( GLenum face, GLenum mode );
+typedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETPROC) ( GLfloat factor, GLfloat units );
+typedef void (APIENTRYP RGLSYMGLPOLYGONSTIPPLEPROC) ( const GLubyte *mask );
+typedef void (APIENTRYP RGLSYMGLGETPOLYGONSTIPPLEPROC) ( GLubyte *mask );
+typedef void (APIENTRYP RGLSYMGLEDGEFLAGPROC) ( GLboolean flag );
+typedef void (APIENTRYP RGLSYMGLEDGEFLAGVPROC) ( const GLboolean *flag );
+typedef void (APIENTRYP RGLSYMGLSCISSORPROC) ( GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (APIENTRYP RGLSYMGLCLIPPLANEPROC) ( GLenum plane, const GLdouble *equation );
+typedef void (APIENTRYP RGLSYMGLGETCLIPPLANEPROC) ( GLenum plane, GLdouble *equation );
+typedef void (APIENTRYP RGLSYMGLDRAWBUFFERPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLREADBUFFERPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLENABLEPROC) ( GLenum cap );
+typedef void (APIENTRYP RGLSYMGLDISABLEPROC) ( GLenum cap );
+typedef GLboolean (APIENTRYP RGLSYMGLISENABLEDPROC) ( GLenum cap );
+typedef void (APIENTRYP RGLSYMGLENABLECLIENTSTATEPROC) ( GLenum cap );
+typedef void (APIENTRYP RGLSYMGLDISABLECLIENTSTATEPROC) ( GLenum cap );
+typedef void (APIENTRYP RGLSYMGLGETBOOLEANVPROC) ( GLenum pname, GLboolean *params );
+typedef void (APIENTRYP RGLSYMGLGETDOUBLEVPROC) ( GLenum pname, GLdouble *params );
+typedef void (APIENTRYP RGLSYMGLGETFLOATVPROC) ( GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETINTEGERVPROC) ( GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLPUSHATTRIBPROC) ( GLbitfield mask );
+typedef void (APIENTRYP RGLSYMGLPOPATTRIBPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLPUSHCLIENTATTRIBPROC) ( GLbitfield mask );
+typedef void (APIENTRYP RGLSYMGLPOPCLIENTATTRIBPROC) ( void );
+typedef GLint (APIENTRYP RGLSYMGLRENDERMODEPROC) ( GLenum mode );
+typedef GLenum (APIENTRYP RGLSYMGLGETERRORPROC) ( void );
+typedef const GLubyte * (APIENTRYP RGLSYMGLGETSTRINGPROC) ( GLenum name );
+typedef void (APIENTRYP RGLSYMGLFINISHPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLFLUSHPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLHINTPROC) ( GLenum target, GLenum mode );
+typedef void (APIENTRYP RGLSYMGLCLEARDEPTHPROC) ( GLclampd depth );
+typedef void (APIENTRYP RGLSYMGLDEPTHFUNCPROC) ( GLenum func );
+typedef void (APIENTRYP RGLSYMGLDEPTHMASKPROC) ( GLboolean flag );
+typedef void (APIENTRYP RGLSYMGLDEPTHRANGEPROC) ( GLclampd near_val, GLclampd far_val );
+typedef void (APIENTRYP RGLSYMGLCLEARACCUMPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
+typedef void (APIENTRYP RGLSYMGLACCUMPROC) ( GLenum op, GLfloat value );
+typedef void (APIENTRYP RGLSYMGLMATRIXMODEPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLORTHOPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );
+typedef void (APIENTRYP RGLSYMGLFRUSTUMPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );
+typedef void (APIENTRYP RGLSYMGLVIEWPORTPROC) ( GLint x, GLint y, GLsizei width, GLsizei height );
+typedef void (APIENTRYP RGLSYMGLPUSHMATRIXPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLPOPMATRIXPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLLOADIDENTITYPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLLOADMATRIXDPROC) ( const GLdouble *m );
+typedef void (APIENTRYP RGLSYMGLLOADMATRIXFPROC) ( const GLfloat *m );
+typedef void (APIENTRYP RGLSYMGLMULTMATRIXDPROC) ( const GLdouble *m );
+typedef void (APIENTRYP RGLSYMGLMULTMATRIXFPROC) ( const GLfloat *m );
+typedef void (APIENTRYP RGLSYMGLROTATEDPROC) ( GLdouble angle, GLdouble x, GLdouble y, GLdouble z );
+typedef void (APIENTRYP RGLSYMGLROTATEFPROC) ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
+typedef void (APIENTRYP RGLSYMGLSCALEDPROC) ( GLdouble x, GLdouble y, GLdouble z );
+typedef void (APIENTRYP RGLSYMGLSCALEFPROC) ( GLfloat x, GLfloat y, GLfloat z );
+typedef void (APIENTRYP RGLSYMGLTRANSLATEDPROC) ( GLdouble x, GLdouble y, GLdouble z );
+typedef void (APIENTRYP RGLSYMGLTRANSLATEFPROC) ( GLfloat x, GLfloat y, GLfloat z );
+typedef GLboolean (APIENTRYP RGLSYMGLISLISTPROC) ( GLuint list );
+typedef void (APIENTRYP RGLSYMGLDELETELISTSPROC) ( GLuint list, GLsizei range );
+typedef GLuint (APIENTRYP RGLSYMGLGENLISTSPROC) ( GLsizei range );
+typedef void (APIENTRYP RGLSYMGLNEWLISTPROC) ( GLuint list, GLenum mode );
+typedef void (APIENTRYP RGLSYMGLENDLISTPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLCALLLISTPROC) ( GLuint list );
+typedef void (APIENTRYP RGLSYMGLCALLLISTSPROC) ( GLsizei n, GLenum type, const GLvoid *lists );
+typedef void (APIENTRYP RGLSYMGLLISTBASEPROC) ( GLuint base );
+typedef void (APIENTRYP RGLSYMGLBEGINPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLENDPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLVERTEX2DPROC) ( GLdouble x, GLdouble y );
+typedef void (APIENTRYP RGLSYMGLVERTEX2FPROC) ( GLfloat x, GLfloat y );
+typedef void (APIENTRYP RGLSYMGLVERTEX2IPROC) ( GLint x, GLint y );
+typedef void (APIENTRYP RGLSYMGLVERTEX2SPROC) ( GLshort x, GLshort y );
+typedef void (APIENTRYP RGLSYMGLVERTEX3DPROC) ( GLdouble x, GLdouble y, GLdouble z );
+typedef void (APIENTRYP RGLSYMGLVERTEX3FPROC) ( GLfloat x, GLfloat y, GLfloat z );
+typedef void (APIENTRYP RGLSYMGLVERTEX3IPROC) ( GLint x, GLint y, GLint z );
+typedef void (APIENTRYP RGLSYMGLVERTEX3SPROC) ( GLshort x, GLshort y, GLshort z );
+typedef void (APIENTRYP RGLSYMGLVERTEX4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
+typedef void (APIENTRYP RGLSYMGLVERTEX4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+typedef void (APIENTRYP RGLSYMGLVERTEX4IPROC) ( GLint x, GLint y, GLint z, GLint w );
+typedef void (APIENTRYP RGLSYMGLVERTEX4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );
+typedef void (APIENTRYP RGLSYMGLVERTEX2DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX2FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX2IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX2SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX3DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX3FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX3IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX3SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX4DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX4FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX4IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLVERTEX4SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLNORMAL3BPROC) ( GLbyte nx, GLbyte ny, GLbyte nz );
+typedef void (APIENTRYP RGLSYMGLNORMAL3DPROC) ( GLdouble nx, GLdouble ny, GLdouble nz );
+typedef void (APIENTRYP RGLSYMGLNORMAL3FPROC) ( GLfloat nx, GLfloat ny, GLfloat nz );
+typedef void (APIENTRYP RGLSYMGLNORMAL3IPROC) ( GLint nx, GLint ny, GLint nz );
+typedef void (APIENTRYP RGLSYMGLNORMAL3SPROC) ( GLshort nx, GLshort ny, GLshort nz );
+typedef void (APIENTRYP RGLSYMGLNORMAL3BVPROC) ( const GLbyte *v );
+typedef void (APIENTRYP RGLSYMGLNORMAL3DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLNORMAL3FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLNORMAL3IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLNORMAL3SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLINDEXDPROC) ( GLdouble c );
+typedef void (APIENTRYP RGLSYMGLINDEXFPROC) ( GLfloat c );
+typedef void (APIENTRYP RGLSYMGLINDEXIPROC) ( GLint c );
+typedef void (APIENTRYP RGLSYMGLINDEXSPROC) ( GLshort c );
+typedef void (APIENTRYP RGLSYMGLINDEXUBPROC) ( GLubyte c );
+typedef void (APIENTRYP RGLSYMGLINDEXDVPROC) ( const GLdouble *c );
+typedef void (APIENTRYP RGLSYMGLINDEXFVPROC) ( const GLfloat *c );
+typedef void (APIENTRYP RGLSYMGLINDEXIVPROC) ( const GLint *c );
+typedef void (APIENTRYP RGLSYMGLINDEXSVPROC) ( const GLshort *c );
+typedef void (APIENTRYP RGLSYMGLINDEXUBVPROC) ( const GLubyte *c );
+typedef void (APIENTRYP RGLSYMGLCOLOR3BPROC) ( GLbyte red, GLbyte green, GLbyte blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR3DPROC) ( GLdouble red, GLdouble green, GLdouble blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR3FPROC) ( GLfloat red, GLfloat green, GLfloat blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR3IPROC) ( GLint red, GLint green, GLint blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR3SPROC) ( GLshort red, GLshort green, GLshort blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR3UBPROC) ( GLubyte red, GLubyte green, GLubyte blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR3UIPROC) ( GLuint red, GLuint green, GLuint blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR3USPROC) ( GLushort red, GLushort green, GLushort blue );
+typedef void (APIENTRYP RGLSYMGLCOLOR4BPROC) ( GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR4DPROC) ( GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR4FPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR4IPROC) ( GLint red, GLint green, GLint blue, GLint alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR4SPROC) ( GLshort red, GLshort green, GLshort blue, GLshort alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR4UBPROC) ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR4UIPROC) ( GLuint red, GLuint green, GLuint blue, GLuint alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR4USPROC) ( GLushort red, GLushort green, GLushort blue, GLushort alpha );
+typedef void (APIENTRYP RGLSYMGLCOLOR3BVPROC) ( const GLbyte *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR3DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR3FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR3IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR3SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR3UBVPROC) ( const GLubyte *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR3UIVPROC) ( const GLuint *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR3USVPROC) ( const GLushort *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4BVPROC) ( const GLbyte *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4UBVPROC) ( const GLubyte *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4UIVPROC) ( const GLuint *v );
+typedef void (APIENTRYP RGLSYMGLCOLOR4USVPROC) ( const GLushort *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1DPROC) ( GLdouble s );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1FPROC) ( GLfloat s );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1IPROC) ( GLint s );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1SPROC) ( GLshort s );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2DPROC) ( GLdouble s, GLdouble t );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2FPROC) ( GLfloat s, GLfloat t );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2IPROC) ( GLint s, GLint t );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2SPROC) ( GLshort s, GLshort t );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3DPROC) ( GLdouble s, GLdouble t, GLdouble r );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3FPROC) ( GLfloat s, GLfloat t, GLfloat r );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3IPROC) ( GLint s, GLint t, GLint r );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3SPROC) ( GLshort s, GLshort t, GLshort r );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4DPROC) ( GLdouble s, GLdouble t, GLdouble r, GLdouble q );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4FPROC) ( GLfloat s, GLfloat t, GLfloat r, GLfloat q );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4IPROC) ( GLint s, GLint t, GLint r, GLint q );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4SPROC) ( GLshort s, GLshort t, GLshort r, GLshort q );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD1SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD2SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD3SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLTEXCOORD4SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2DPROC) ( GLdouble x, GLdouble y );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2FPROC) ( GLfloat x, GLfloat y );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2IPROC) ( GLint x, GLint y );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2SPROC) ( GLshort x, GLshort y );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3DPROC) ( GLdouble x, GLdouble y, GLdouble z );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3FPROC) ( GLfloat x, GLfloat y, GLfloat z );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3IPROC) ( GLint x, GLint y, GLint z );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3SPROC) ( GLshort x, GLshort y, GLshort z );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4IPROC) ( GLint x, GLint y, GLint z, GLint w );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS2SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS3SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4DVPROC) ( const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4FVPROC) ( const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4IVPROC) ( const GLint *v );
+typedef void (APIENTRYP RGLSYMGLRASTERPOS4SVPROC) ( const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLRECTDPROC) ( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 );
+typedef void (APIENTRYP RGLSYMGLRECTFPROC) ( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 );
+typedef void (APIENTRYP RGLSYMGLRECTIPROC) ( GLint x1, GLint y1, GLint x2, GLint y2 );
+typedef void (APIENTRYP RGLSYMGLRECTSPROC) ( GLshort x1, GLshort y1, GLshort x2, GLshort y2 );
+typedef void (APIENTRYP RGLSYMGLRECTDVPROC) ( const GLdouble *v1, const GLdouble *v2 );
+typedef void (APIENTRYP RGLSYMGLRECTFVPROC) ( const GLfloat *v1, const GLfloat *v2 );
+typedef void (APIENTRYP RGLSYMGLRECTIVPROC) ( const GLint *v1, const GLint *v2 );
+typedef void (APIENTRYP RGLSYMGLRECTSVPROC) ( const GLshort *v1, const GLshort *v2 );
+typedef void (APIENTRYP RGLSYMGLVERTEXPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
+typedef void (APIENTRYP RGLSYMGLNORMALPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );
+typedef void (APIENTRYP RGLSYMGLCOLORPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
+typedef void (APIENTRYP RGLSYMGLINDEXPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );
+typedef void (APIENTRYP RGLSYMGLTEXCOORDPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
+typedef void (APIENTRYP RGLSYMGLEDGEFLAGPOINTERPROC) ( GLsizei stride, const GLvoid *ptr );
+typedef void (APIENTRYP RGLSYMGLGETPOINTERVPROC) ( GLenum pname, GLvoid **params );
+typedef void (APIENTRYP RGLSYMGLARRAYELEMENTPROC) ( GLint i );
+typedef void (APIENTRYP RGLSYMGLDRAWARRAYSPROC) ( GLenum mode, GLint first, GLsizei count );
+typedef void (APIENTRYP RGLSYMGLDRAWELEMENTSPROC) ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices );
+typedef void (APIENTRYP RGLSYMGLINTERLEAVEDARRAYSPROC) ( GLenum format, GLsizei stride, const GLvoid *pointer );
+typedef void (APIENTRYP RGLSYMGLSHADEMODELPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLLIGHTFPROC) ( GLenum light, GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLLIGHTIPROC) ( GLenum light, GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLLIGHTFVPROC) ( GLenum light, GLenum pname, const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLLIGHTIVPROC) ( GLenum light, GLenum pname, const GLint *params );
+typedef void (APIENTRYP RGLSYMGLGETLIGHTFVPROC) ( GLenum light, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETLIGHTIVPROC) ( GLenum light, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLLIGHTMODELFPROC) ( GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLLIGHTMODELIPROC) ( GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLLIGHTMODELFVPROC) ( GLenum pname, const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLLIGHTMODELIVPROC) ( GLenum pname, const GLint *params );
+typedef void (APIENTRYP RGLSYMGLMATERIALFPROC) ( GLenum face, GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLMATERIALIPROC) ( GLenum face, GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLMATERIALFVPROC) ( GLenum face, GLenum pname, const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLMATERIALIVPROC) ( GLenum face, GLenum pname, const GLint *params );
+typedef void (APIENTRYP RGLSYMGLGETMATERIALFVPROC) ( GLenum face, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETMATERIALIVPROC) ( GLenum face, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLCOLORMATERIALPROC) ( GLenum face, GLenum mode );
+typedef void (APIENTRYP RGLSYMGLPIXELZOOMPROC) ( GLfloat xfactor, GLfloat yfactor );
+typedef void (APIENTRYP RGLSYMGLPIXELSTOREFPROC) ( GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLPIXELSTOREIPROC) ( GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERFPROC) ( GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLPIXELTRANSFERIPROC) ( GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLPIXELMAPFVPROC) ( GLenum map, GLsizei mapsize, const GLfloat *values );
+typedef void (APIENTRYP RGLSYMGLPIXELMAPUIVPROC) ( GLenum map, GLsizei mapsize, const GLuint *values );
+typedef void (APIENTRYP RGLSYMGLPIXELMAPUSVPROC) ( GLenum map, GLsizei mapsize, const GLushort *values );
+typedef void (APIENTRYP RGLSYMGLGETPIXELMAPFVPROC) ( GLenum map, GLfloat *values );
+typedef void (APIENTRYP RGLSYMGLGETPIXELMAPUIVPROC) ( GLenum map, GLuint *values );
+typedef void (APIENTRYP RGLSYMGLGETPIXELMAPUSVPROC) ( GLenum map, GLushort *values );
+typedef void (APIENTRYP RGLSYMGLBITMAPPROC) ( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap );
+typedef void (APIENTRYP RGLSYMGLREADPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLDRAWPIXELSPROC) ( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLCOPYPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type );
+typedef void (APIENTRYP RGLSYMGLSTENCILFUNCPROC) ( GLenum func, GLint ref, GLuint mask );
+typedef void (APIENTRYP RGLSYMGLSTENCILMASKPROC) ( GLuint mask );
+typedef void (APIENTRYP RGLSYMGLSTENCILOPPROC) ( GLenum fail, GLenum zfail, GLenum zpass );
+typedef void (APIENTRYP RGLSYMGLCLEARSTENCILPROC) ( GLint s );
+typedef void (APIENTRYP RGLSYMGLTEXGENDPROC) ( GLenum coord, GLenum pname, GLdouble param );
+typedef void (APIENTRYP RGLSYMGLTEXGENFPROC) ( GLenum coord, GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLTEXGENIPROC) ( GLenum coord, GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLTEXGENDVPROC) ( GLenum coord, GLenum pname, const GLdouble *params );
+typedef void (APIENTRYP RGLSYMGLTEXGENFVPROC) ( GLenum coord, GLenum pname, const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLTEXGENIVPROC) ( GLenum coord, GLenum pname, const GLint *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXGENDVPROC) ( GLenum coord, GLenum pname, GLdouble *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXGENFVPROC) ( GLenum coord, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXGENIVPROC) ( GLenum coord, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLTEXENVFPROC) ( GLenum target, GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLTEXENVIPROC) ( GLenum target, GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLTEXENVFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLTEXENVIVPROC) ( GLenum target, GLenum pname, const GLint *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXENVFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXENVIVPROC) ( GLenum target, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERFPROC) ( GLenum target, GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIPROC) ( GLenum target, GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, const GLint *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERFVPROC) ( GLenum target, GLint level, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERIVPROC) ( GLenum target, GLint level, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLTEXIMAGE1DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLTEXIMAGE2DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLGETTEXIMAGEPROC) ( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLGENTEXTURESPROC) ( GLsizei n, GLuint *textures );
+typedef void (APIENTRYP RGLSYMGLDELETETEXTURESPROC) ( GLsizei n, const GLuint *textures);
+typedef void (APIENTRYP RGLSYMGLBINDTEXTUREPROC) ( GLenum target, GLuint texture );
+typedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESPROC) ( GLsizei n, const GLuint *textures, const GLclampf *priorities );
+typedef GLboolean (APIENTRYP RGLSYMGLARETEXTURESRESIDENTPROC) ( GLsizei n, const GLuint *textures, GLboolean *residences );
+typedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREPROC) ( GLuint texture );
+typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border );
+typedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border );
+typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width );
+typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height );
+typedef void (APIENTRYP RGLSYMGLMAP1DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points );
+typedef void (APIENTRYP RGLSYMGLMAP1FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points );
+typedef void (APIENTRYP RGLSYMGLMAP2DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points );
+typedef void (APIENTRYP RGLSYMGLMAP2FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points );
+typedef void (APIENTRYP RGLSYMGLGETMAPDVPROC) ( GLenum target, GLenum query, GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLGETMAPFVPROC) ( GLenum target, GLenum query, GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLGETMAPIVPROC) ( GLenum target, GLenum query, GLint *v );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD1DPROC) ( GLdouble u );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD1FPROC) ( GLfloat u );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD1DVPROC) ( const GLdouble *u );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD1FVPROC) ( const GLfloat *u );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD2DPROC) ( GLdouble u, GLdouble v );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD2FPROC) ( GLfloat u, GLfloat v );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD2DVPROC) ( const GLdouble *u );
+typedef void (APIENTRYP RGLSYMGLEVALCOORD2FVPROC) ( const GLfloat *u );
+typedef void (APIENTRYP RGLSYMGLMAPGRID1DPROC) ( GLint un, GLdouble u1, GLdouble u2 );
+typedef void (APIENTRYP RGLSYMGLMAPGRID1FPROC) ( GLint un, GLfloat u1, GLfloat u2 );
+typedef void (APIENTRYP RGLSYMGLMAPGRID2DPROC) ( GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2 );
+typedef void (APIENTRYP RGLSYMGLMAPGRID2FPROC) ( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 );
+typedef void (APIENTRYP RGLSYMGLEVALPOINT1PROC) ( GLint i );
+typedef void (APIENTRYP RGLSYMGLEVALPOINT2PROC) ( GLint i, GLint j );
+typedef void (APIENTRYP RGLSYMGLEVALMESH1PROC) ( GLenum mode, GLint i1, GLint i2 );
+typedef void (APIENTRYP RGLSYMGLEVALMESH2PROC) ( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 );
+typedef void (APIENTRYP RGLSYMGLFOGFPROC) ( GLenum pname, GLfloat param );
+typedef void (APIENTRYP RGLSYMGLFOGIPROC) ( GLenum pname, GLint param );
+typedef void (APIENTRYP RGLSYMGLFOGFVPROC) ( GLenum pname, const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLFOGIVPROC) ( GLenum pname, const GLint *params );
+typedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERPROC) ( GLsizei size, GLenum type, GLfloat *buffer );
+typedef void (APIENTRYP RGLSYMGLPASSTHROUGHPROC) ( GLfloat token );
+typedef void (APIENTRYP RGLSYMGLSELECTBUFFERPROC) ( GLsizei size, GLuint *buffer );
+typedef void (APIENTRYP RGLSYMGLINITNAMESPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLLOADNAMEPROC) ( GLuint name );
+typedef void (APIENTRYP RGLSYMGLPUSHNAMEPROC) ( GLuint name );
+typedef void (APIENTRYP RGLSYMGLPOPNAMEPROC) ( void );
+typedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) ( GLenum mode, GLuint start,GLuint end, GLsizei count, GLenum type, const GLvoid *indices );
+typedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
+typedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height );
+typedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table );
+typedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data );
+typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
+typedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
+typedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLint x, GLint y, GLsizei width );
+typedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width );
+typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) ( GLenum target, GLenum format, GLenum type, GLvoid *table );
+typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) ( GLenum mode );
+typedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
+typedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) ( GLenum target, GLsizei width, GLenum internalformat, GLboolean sink );
+typedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) ( GLenum target );
+typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values );
+typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLMINMAXPROC) ( GLenum target, GLenum internalformat,GLboolean sink );
+typedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) ( GLenum target );
+typedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values );
+typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLenum format, GLenum type,const GLvoid *image );
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *image );
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) ( GLenum target, GLenum pname,GLfloat params );
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,const GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) ( GLenum target, GLenum pname,GLint params );
+typedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,const GLint *params );
+typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width );
+typedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width,GLsizei height);
+typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *image );
+typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,GLfloat *params );
+typedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,GLint *params );
+typedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *row, const GLvoid *column );
+typedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *row, GLvoid *column, GLvoid *span );
+typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) ( GLenum texture );
+typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) ( GLenum texture );
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data );
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data );
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data );
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data );
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data );
+typedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data );
+typedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) ( GLenum target, GLint lod, GLvoid *img );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) ( GLenum target, GLdouble s );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) ( GLenum target, const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) ( GLenum target, GLfloat s );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) ( GLenum target, const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) ( GLenum target, GLint s );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) ( GLenum target, const GLint *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) ( GLenum target, GLshort s );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) ( GLenum target, const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) ( GLenum target, GLdouble s, GLdouble t );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) ( GLenum target, const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) ( GLenum target, GLfloat s, GLfloat t );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) ( GLenum target, const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) ( GLenum target, GLint s, GLint t );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) ( GLenum target, const GLint *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) ( GLenum target, GLshort s, GLshort t );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) ( GLenum target, const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) ( GLenum target, const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) ( GLenum target, const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) ( GLenum target, GLint s, GLint t, GLint r );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) ( GLenum target, const GLint *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) ( GLenum target, const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) ( GLenum target, const GLdouble *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) ( GLenum target, const GLfloat *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) ( GLenum target, GLint s, GLint t, GLint r, GLint q );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) ( GLenum target, const GLint *v );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r, GLshort q );
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) ( GLenum target, const GLshort *v );
+typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );
+typedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );
+typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );
+typedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );
+typedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) ( GLclampf value, GLboolean invert );
+typedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);
+typedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);
+typedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
+
+RGLSYMGLCLEARINDEXPROC glClearIndex;
+RGLSYMGLCLEARCOLORPROC glClearColor;
+RGLSYMGLCLEARPROC glClear;
+RGLSYMGLINDEXMASKPROC glIndexMask;
+RGLSYMGLCOLORMASKPROC glColorMask;
+RGLSYMGLALPHAFUNCPROC glAlphaFunc;
+RGLSYMGLBLENDFUNCPROC glBlendFunc;
+RGLSYMGLLOGICOPPROC glLogicOp;
+RGLSYMGLCULLFACEPROC glCullFace;
+RGLSYMGLFRONTFACEPROC glFrontFace;
+RGLSYMGLPOINTSIZEPROC glPointSize;
+RGLSYMGLLINEWIDTHPROC glLineWidth;
+RGLSYMGLLINESTIPPLEPROC glLineStipple;
+RGLSYMGLPOLYGONMODEPROC glPolygonMode;
+RGLSYMGLPOLYGONOFFSETPROC glPolygonOffset;
+RGLSYMGLPOLYGONSTIPPLEPROC glPolygonStipple;
+RGLSYMGLGETPOLYGONSTIPPLEPROC glGetPolygonStipple;
+RGLSYMGLEDGEFLAGPROC glEdgeFlag;
+RGLSYMGLEDGEFLAGVPROC glEdgeFlagv;
+RGLSYMGLSCISSORPROC glScissor;
+RGLSYMGLCLIPPLANEPROC glClipPlane;
+RGLSYMGLGETCLIPPLANEPROC glGetClipPlane;
+RGLSYMGLDRAWBUFFERPROC glDrawBuffer;
+RGLSYMGLREADBUFFERPROC glReadBuffer;
+RGLSYMGLENABLEPROC glEnable;
+RGLSYMGLDISABLEPROC glDisable;
+RGLSYMGLISENABLEDPROC glIsEnabled;
+RGLSYMGLENABLECLIENTSTATEPROC glEnableClientState;
+RGLSYMGLDISABLECLIENTSTATEPROC glDisableClientState;
+RGLSYMGLGETBOOLEANVPROC glGetBooleanv;
+RGLSYMGLGETDOUBLEVPROC glGetDoublev;
+RGLSYMGLGETFLOATVPROC glGetFloatv;
+RGLSYMGLGETINTEGERVPROC glGetIntegerv;
+RGLSYMGLPUSHATTRIBPROC glPushAttrib;
+RGLSYMGLPOPATTRIBPROC glPopAttrib;
+RGLSYMGLPUSHCLIENTATTRIBPROC glPushClientAttrib;
+RGLSYMGLPOPCLIENTATTRIBPROC glPopClientAttrib;
+RGLSYMGLRENDERMODEPROC glRenderMode;
+RGLSYMGLGETERRORPROC glGetError;
+RGLSYMGLGETSTRINGPROC glGetString;
+RGLSYMGLFINISHPROC glFinish;
+RGLSYMGLFLUSHPROC glFlush;
+RGLSYMGLHINTPROC glHint;
+RGLSYMGLCLEARDEPTHPROC glClearDepth;
+RGLSYMGLDEPTHFUNCPROC glDepthFunc;
+RGLSYMGLDEPTHMASKPROC glDepthMask;
+RGLSYMGLDEPTHRANGEPROC glDepthRange;
+RGLSYMGLCLEARACCUMPROC glClearAccum;
+RGLSYMGLACCUMPROC glAccum;
+RGLSYMGLMATRIXMODEPROC glMatrixMode;
+RGLSYMGLORTHOPROC glOrtho;
+RGLSYMGLFRUSTUMPROC glFrustum;
+RGLSYMGLVIEWPORTPROC glViewport;
+RGLSYMGLPUSHMATRIXPROC glPushMatrix;
+RGLSYMGLPOPMATRIXPROC glPopMatrix;
+RGLSYMGLLOADIDENTITYPROC glLoadIdentity;
+RGLSYMGLLOADMATRIXDPROC glLoadMatrixd;
+RGLSYMGLLOADMATRIXFPROC glLoadMatrixf;
+RGLSYMGLMULTMATRIXDPROC glMultMatrixd;
+RGLSYMGLMULTMATRIXFPROC glMultMatrixf;
+RGLSYMGLROTATEDPROC glRotated;
+RGLSYMGLROTATEFPROC glRotatef;
+RGLSYMGLSCALEDPROC glScaled;
+RGLSYMGLSCALEFPROC glScalef;
+RGLSYMGLTRANSLATEDPROC glTranslated;
+RGLSYMGLTRANSLATEFPROC glTranslatef;
+RGLSYMGLISLISTPROC glIsList;
+RGLSYMGLDELETELISTSPROC glDeleteLists;
+RGLSYMGLGENLISTSPROC glGenLists;
+RGLSYMGLNEWLISTPROC glNewList;
+RGLSYMGLENDLISTPROC glEndList;
+RGLSYMGLCALLLISTPROC glCallList;
+RGLSYMGLCALLLISTSPROC glCallLists;
+RGLSYMGLLISTBASEPROC glListBase;
+RGLSYMGLBEGINPROC glBegin;
+RGLSYMGLENDPROC glEnd;
+RGLSYMGLVERTEX2DPROC glVertex2d;
+RGLSYMGLVERTEX2FPROC glVertex2f;
+RGLSYMGLVERTEX2IPROC glVertex2i;
+RGLSYMGLVERTEX2SPROC glVertex2s;
+RGLSYMGLVERTEX3DPROC glVertex3d;
+RGLSYMGLVERTEX3FPROC glVertex3f;
+RGLSYMGLVERTEX3IPROC glVertex3i;
+RGLSYMGLVERTEX3SPROC glVertex3s;
+RGLSYMGLVERTEX4DPROC glVertex4d;
+RGLSYMGLVERTEX4FPROC glVertex4f;
+RGLSYMGLVERTEX4IPROC glVertex4i;
+RGLSYMGLVERTEX4SPROC glVertex4s;
+RGLSYMGLVERTEX2DVPROC glVertex2dv;
+RGLSYMGLVERTEX2FVPROC glVertex2fv;
+RGLSYMGLVERTEX2IVPROC glVertex2iv;
+RGLSYMGLVERTEX2SVPROC glVertex2sv;
+RGLSYMGLVERTEX3DVPROC glVertex3dv;
+RGLSYMGLVERTEX3FVPROC glVertex3fv;
+RGLSYMGLVERTEX3IVPROC glVertex3iv;
+RGLSYMGLVERTEX3SVPROC glVertex3sv;
+RGLSYMGLVERTEX4DVPROC glVertex4dv;
+RGLSYMGLVERTEX4FVPROC glVertex4fv;
+RGLSYMGLVERTEX4IVPROC glVertex4iv;
+RGLSYMGLVERTEX4SVPROC glVertex4sv;
+RGLSYMGLNORMAL3BPROC glNormal3b;
+RGLSYMGLNORMAL3DPROC glNormal3d;
+RGLSYMGLNORMAL3FPROC glNormal3f;
+RGLSYMGLNORMAL3IPROC glNormal3i;
+RGLSYMGLNORMAL3SPROC glNormal3s;
+RGLSYMGLNORMAL3BVPROC glNormal3bv;
+RGLSYMGLNORMAL3DVPROC glNormal3dv;
+RGLSYMGLNORMAL3FVPROC glNormal3fv;
+RGLSYMGLNORMAL3IVPROC glNormal3iv;
+RGLSYMGLNORMAL3SVPROC glNormal3sv;
+RGLSYMGLINDEXDPROC glIndexd;
+RGLSYMGLINDEXFPROC glIndexf;
+RGLSYMGLINDEXIPROC glIndexi;
+RGLSYMGLINDEXSPROC glIndexs;
+RGLSYMGLINDEXUBPROC glIndexub;
+RGLSYMGLINDEXDVPROC glIndexdv;
+RGLSYMGLINDEXFVPROC glIndexfv;
+RGLSYMGLINDEXIVPROC glIndexiv;
+RGLSYMGLINDEXSVPROC glIndexsv;
+RGLSYMGLINDEXUBVPROC glIndexubv;
+RGLSYMGLCOLOR3BPROC glColor3b;
+RGLSYMGLCOLOR3DPROC glColor3d;
+RGLSYMGLCOLOR3FPROC glColor3f;
+RGLSYMGLCOLOR3IPROC glColor3i;
+RGLSYMGLCOLOR3SPROC glColor3s;
+RGLSYMGLCOLOR3UBPROC glColor3ub;
+RGLSYMGLCOLOR3UIPROC glColor3ui;
+RGLSYMGLCOLOR3USPROC glColor3us;
+RGLSYMGLCOLOR4BPROC glColor4b;
+RGLSYMGLCOLOR4DPROC glColor4d;
+RGLSYMGLCOLOR4FPROC glColor4f;
+RGLSYMGLCOLOR4IPROC glColor4i;
+RGLSYMGLCOLOR4SPROC glColor4s;
+RGLSYMGLCOLOR4UBPROC glColor4ub;
+RGLSYMGLCOLOR4UIPROC glColor4ui;
+RGLSYMGLCOLOR4USPROC glColor4us;
+RGLSYMGLCOLOR3BVPROC glColor3bv;
+RGLSYMGLCOLOR3DVPROC glColor3dv;
+RGLSYMGLCOLOR3FVPROC glColor3fv;
+RGLSYMGLCOLOR3IVPROC glColor3iv;
+RGLSYMGLCOLOR3SVPROC glColor3sv;
+RGLSYMGLCOLOR3UBVPROC glColor3ubv;
+RGLSYMGLCOLOR3UIVPROC glColor3uiv;
+RGLSYMGLCOLOR3USVPROC glColor3usv;
+RGLSYMGLCOLOR4BVPROC glColor4bv;
+RGLSYMGLCOLOR4DVPROC glColor4dv;
+RGLSYMGLCOLOR4FVPROC glColor4fv;
+RGLSYMGLCOLOR4IVPROC glColor4iv;
+RGLSYMGLCOLOR4SVPROC glColor4sv;
+RGLSYMGLCOLOR4UBVPROC glColor4ubv;
+RGLSYMGLCOLOR4UIVPROC glColor4uiv;
+RGLSYMGLCOLOR4USVPROC glColor4usv;
+RGLSYMGLTEXCOORD1DPROC glTexCoord1d;
+RGLSYMGLTEXCOORD1FPROC glTexCoord1f;
+RGLSYMGLTEXCOORD1IPROC glTexCoord1i;
+RGLSYMGLTEXCOORD1SPROC glTexCoord1s;
+RGLSYMGLTEXCOORD2DPROC glTexCoord2d;
+RGLSYMGLTEXCOORD2FPROC glTexCoord2f;
+RGLSYMGLTEXCOORD2IPROC glTexCoord2i;
+RGLSYMGLTEXCOORD2SPROC glTexCoord2s;
+RGLSYMGLTEXCOORD3DPROC glTexCoord3d;
+RGLSYMGLTEXCOORD3FPROC glTexCoord3f;
+RGLSYMGLTEXCOORD3IPROC glTexCoord3i;
+RGLSYMGLTEXCOORD3SPROC glTexCoord3s;
+RGLSYMGLTEXCOORD4DPROC glTexCoord4d;
+RGLSYMGLTEXCOORD4FPROC glTexCoord4f;
+RGLSYMGLTEXCOORD4IPROC glTexCoord4i;
+RGLSYMGLTEXCOORD4SPROC glTexCoord4s;
+RGLSYMGLTEXCOORD1DVPROC glTexCoord1dv;
+RGLSYMGLTEXCOORD1FVPROC glTexCoord1fv;
+RGLSYMGLTEXCOORD1IVPROC glTexCoord1iv;
+RGLSYMGLTEXCOORD1SVPROC glTexCoord1sv;
+RGLSYMGLTEXCOORD2DVPROC glTexCoord2dv;
+RGLSYMGLTEXCOORD2FVPROC glTexCoord2fv;
+RGLSYMGLTEXCOORD2IVPROC glTexCoord2iv;
+RGLSYMGLTEXCOORD2SVPROC glTexCoord2sv;
+RGLSYMGLTEXCOORD3DVPROC glTexCoord3dv;
+RGLSYMGLTEXCOORD3FVPROC glTexCoord3fv;
+RGLSYMGLTEXCOORD3IVPROC glTexCoord3iv;
+RGLSYMGLTEXCOORD3SVPROC glTexCoord3sv;
+RGLSYMGLTEXCOORD4DVPROC glTexCoord4dv;
+RGLSYMGLTEXCOORD4FVPROC glTexCoord4fv;
+RGLSYMGLTEXCOORD4IVPROC glTexCoord4iv;
+RGLSYMGLTEXCOORD4SVPROC glTexCoord4sv;
+RGLSYMGLRASTERPOS2DPROC glRasterPos2d;
+RGLSYMGLRASTERPOS2FPROC glRasterPos2f;
+RGLSYMGLRASTERPOS2IPROC glRasterPos2i;
+RGLSYMGLRASTERPOS2SPROC glRasterPos2s;
+RGLSYMGLRASTERPOS3DPROC glRasterPos3d;
+RGLSYMGLRASTERPOS3FPROC glRasterPos3f;
+RGLSYMGLRASTERPOS3IPROC glRasterPos3i;
+RGLSYMGLRASTERPOS3SPROC glRasterPos3s;
+RGLSYMGLRASTERPOS4DPROC glRasterPos4d;
+RGLSYMGLRASTERPOS4FPROC glRasterPos4f;
+RGLSYMGLRASTERPOS4IPROC glRasterPos4i;
+RGLSYMGLRASTERPOS4SPROC glRasterPos4s;
+RGLSYMGLRASTERPOS2DVPROC glRasterPos2dv;
+RGLSYMGLRASTERPOS2FVPROC glRasterPos2fv;
+RGLSYMGLRASTERPOS2IVPROC glRasterPos2iv;
+RGLSYMGLRASTERPOS2SVPROC glRasterPos2sv;
+RGLSYMGLRASTERPOS3DVPROC glRasterPos3dv;
+RGLSYMGLRASTERPOS3FVPROC glRasterPos3fv;
+RGLSYMGLRASTERPOS3IVPROC glRasterPos3iv;
+RGLSYMGLRASTERPOS3SVPROC glRasterPos3sv;
+RGLSYMGLRASTERPOS4DVPROC glRasterPos4dv;
+RGLSYMGLRASTERPOS4FVPROC glRasterPos4fv;
+RGLSYMGLRASTERPOS4IVPROC glRasterPos4iv;
+RGLSYMGLRASTERPOS4SVPROC glRasterPos4sv;
+RGLSYMGLRECTDPROC glRectd;
+RGLSYMGLRECTFPROC glRectf;
+RGLSYMGLRECTIPROC glRecti;
+RGLSYMGLRECTSPROC glRects;
+RGLSYMGLRECTDVPROC glRectdv;
+RGLSYMGLRECTFVPROC glRectfv;
+RGLSYMGLRECTIVPROC glRectiv;
+RGLSYMGLRECTSVPROC glRectsv;
+RGLSYMGLVERTEXPOINTERPROC glVertexPointer;
+RGLSYMGLNORMALPOINTERPROC glNormalPointer;
+RGLSYMGLCOLORPOINTERPROC glColorPointer;
+RGLSYMGLINDEXPOINTERPROC glIndexPointer;
+RGLSYMGLTEXCOORDPOINTERPROC glTexCoordPointer;
+RGLSYMGLEDGEFLAGPOINTERPROC glEdgeFlagPointer;
+RGLSYMGLGETPOINTERVPROC glGetPointerv;
+RGLSYMGLARRAYELEMENTPROC glArrayElement;
+RGLSYMGLDRAWARRAYSPROC glDrawArrays;
+RGLSYMGLDRAWELEMENTSPROC glDrawElements;
+RGLSYMGLINTERLEAVEDARRAYSPROC glInterleavedArrays;
+RGLSYMGLSHADEMODELPROC glShadeModel;
+RGLSYMGLLIGHTFPROC glLightf;
+RGLSYMGLLIGHTIPROC glLighti;
+RGLSYMGLLIGHTFVPROC glLightfv;
+RGLSYMGLLIGHTIVPROC glLightiv;
+RGLSYMGLGETLIGHTFVPROC glGetLightfv;
+RGLSYMGLGETLIGHTIVPROC glGetLightiv;
+RGLSYMGLLIGHTMODELFPROC glLightModelf;
+RGLSYMGLLIGHTMODELIPROC glLightModeli;
+RGLSYMGLLIGHTMODELFVPROC glLightModelfv;
+RGLSYMGLLIGHTMODELIVPROC glLightModeliv;
+RGLSYMGLMATERIALFPROC glMaterialf;
+RGLSYMGLMATERIALIPROC glMateriali;
+RGLSYMGLMATERIALFVPROC glMaterialfv;
+RGLSYMGLMATERIALIVPROC glMaterialiv;
+RGLSYMGLGETMATERIALFVPROC glGetMaterialfv;
+RGLSYMGLGETMATERIALIVPROC glGetMaterialiv;
+RGLSYMGLCOLORMATERIALPROC glColorMaterial;
+RGLSYMGLPIXELZOOMPROC glPixelZoom;
+RGLSYMGLPIXELSTOREFPROC glPixelStoref;
+RGLSYMGLPIXELSTOREIPROC glPixelStorei;
+RGLSYMGLPIXELTRANSFERFPROC glPixelTransferf;
+RGLSYMGLPIXELTRANSFERIPROC glPixelTransferi;
+RGLSYMGLPIXELMAPFVPROC glPixelMapfv;
+RGLSYMGLPIXELMAPUIVPROC glPixelMapuiv;
+RGLSYMGLPIXELMAPUSVPROC glPixelMapusv;
+RGLSYMGLGETPIXELMAPFVPROC glGetPixelMapfv;
+RGLSYMGLGETPIXELMAPUIVPROC glGetPixelMapuiv;
+RGLSYMGLGETPIXELMAPUSVPROC glGetPixelMapusv;
+RGLSYMGLBITMAPPROC glBitmap;
+RGLSYMGLREADPIXELSPROC glReadPixels;
+RGLSYMGLDRAWPIXELSPROC glDrawPixels;
+RGLSYMGLCOPYPIXELSPROC glCopyPixels;
+RGLSYMGLSTENCILFUNCPROC glStencilFunc;
+RGLSYMGLSTENCILMASKPROC glStencilMask;
+RGLSYMGLSTENCILOPPROC glStencilOp;
+RGLSYMGLCLEARSTENCILPROC glClearStencil;
+RGLSYMGLTEXGENDPROC glTexGend;
+RGLSYMGLTEXGENFPROC glTexGenf;
+RGLSYMGLTEXGENIPROC glTexGeni;
+RGLSYMGLTEXGENDVPROC glTexGendv;
+RGLSYMGLTEXGENFVPROC glTexGenfv;
+RGLSYMGLTEXGENIVPROC glTexGeniv;
+RGLSYMGLGETTEXGENDVPROC glGetTexGendv;
+RGLSYMGLGETTEXGENFVPROC glGetTexGenfv;
+RGLSYMGLGETTEXGENIVPROC glGetTexGeniv;
+RGLSYMGLTEXENVFPROC glTexEnvf;
+RGLSYMGLTEXENVIPROC glTexEnvi;
+RGLSYMGLTEXENVFVPROC glTexEnvfv;
+RGLSYMGLTEXENVIVPROC glTexEnviv;
+RGLSYMGLGETTEXENVFVPROC glGetTexEnvfv;
+RGLSYMGLGETTEXENVIVPROC glGetTexEnviv;
+RGLSYMGLTEXPARAMETERFPROC glTexParameterf;
+RGLSYMGLTEXPARAMETERIPROC glTexParameteri;
+RGLSYMGLTEXPARAMETERFVPROC glTexParameterfv;
+RGLSYMGLTEXPARAMETERIVPROC glTexParameteriv;
+RGLSYMGLGETTEXPARAMETERFVPROC glGetTexParameterfv;
+RGLSYMGLGETTEXPARAMETERIVPROC glGetTexParameteriv;
+RGLSYMGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv;
+RGLSYMGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv;
+RGLSYMGLTEXIMAGE1DPROC glTexImage1D;
+RGLSYMGLTEXIMAGE2DPROC glTexImage2D;
+RGLSYMGLGETTEXIMAGEPROC glGetTexImage;
+RGLSYMGLGENTEXTURESPROC glGenTextures;
+RGLSYMGLDELETETEXTURESPROC glDeleteTextures;
+RGLSYMGLBINDTEXTUREPROC glBindTexture;
+RGLSYMGLPRIORITIZETEXTURESPROC glPrioritizeTextures;
+RGLSYMGLARETEXTURESRESIDENTPROC glAreTexturesResident;
+RGLSYMGLISTEXTUREPROC glIsTexture;
+RGLSYMGLTEXSUBIMAGE1DPROC glTexSubImage1D;
+RGLSYMGLTEXSUBIMAGE2DPROC glTexSubImage2D;
+RGLSYMGLCOPYTEXIMAGE1DPROC glCopyTexImage1D;
+RGLSYMGLCOPYTEXIMAGE2DPROC glCopyTexImage2D;
+RGLSYMGLCOPYTEXSUBIMAGE1DPROC glCopyTexSubImage1D;
+RGLSYMGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D;
+RGLSYMGLMAP1DPROC glMap1d;
+RGLSYMGLMAP1FPROC glMap1f;
+RGLSYMGLMAP2DPROC glMap2d;
+RGLSYMGLMAP2FPROC glMap2f;
+RGLSYMGLGETMAPDVPROC glGetMapdv;
+RGLSYMGLGETMAPFVPROC glGetMapfv;
+RGLSYMGLGETMAPIVPROC glGetMapiv;
+RGLSYMGLEVALCOORD1DPROC glEvalCoord1d;
+RGLSYMGLEVALCOORD1FPROC glEvalCoord1f;
+RGLSYMGLEVALCOORD1DVPROC glEvalCoord1dv;
+RGLSYMGLEVALCOORD1FVPROC glEvalCoord1fv;
+RGLSYMGLEVALCOORD2DPROC glEvalCoord2d;
+RGLSYMGLEVALCOORD2FPROC glEvalCoord2f;
+RGLSYMGLEVALCOORD2DVPROC glEvalCoord2dv;
+RGLSYMGLEVALCOORD2FVPROC glEvalCoord2fv;
+RGLSYMGLMAPGRID1DPROC glMapGrid1d;
+RGLSYMGLMAPGRID1FPROC glMapGrid1f;
+RGLSYMGLMAPGRID2DPROC glMapGrid2d;
+RGLSYMGLMAPGRID2FPROC glMapGrid2f;
+RGLSYMGLEVALPOINT1PROC glEvalPoint1;
+RGLSYMGLEVALPOINT2PROC glEvalPoint2;
+RGLSYMGLEVALMESH1PROC glEvalMesh1;
+RGLSYMGLEVALMESH2PROC glEvalMesh2;
+RGLSYMGLFOGFPROC glFogf;
+RGLSYMGLFOGIPROC glFogi;
+RGLSYMGLFOGFVPROC glFogfv;
+RGLSYMGLFOGIVPROC glFogiv;
+RGLSYMGLFEEDBACKBUFFERPROC glFeedbackBuffer;
+RGLSYMGLPASSTHROUGHPROC glPassThrough;
+RGLSYMGLSELECTBUFFERPROC glSelectBuffer;
+RGLSYMGLINITNAMESPROC glInitNames;
+RGLSYMGLLOADNAMEPROC glLoadName;
+RGLSYMGLPUSHNAMEPROC glPushName;
+RGLSYMGLPOPNAMEPROC glPopName;
+RGLSYMGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
+RGLSYMGLTEXIMAGE3DPROC glTexImage3D;
+RGLSYMGLTEXSUBIMAGE3DPROC glTexSubImage3D;
+RGLSYMGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D;
+RGLSYMGLCOLORTABLEPROC glColorTable;
+RGLSYMGLCOLORSUBTABLEPROC glColorSubTable;
+RGLSYMGLCOLORTABLEPARAMETERIVPROC glColorTableParameteriv;
+RGLSYMGLCOLORTABLEPARAMETERFVPROC glColorTableParameterfv;
+RGLSYMGLCOPYCOLORSUBTABLEPROC glCopyColorSubTable;
+RGLSYMGLCOPYCOLORTABLEPROC glCopyColorTable;
+RGLSYMGLGETCOLORTABLEPROC glGetColorTable;
+RGLSYMGLGETCOLORTABLEPARAMETERFVPROC glGetColorTableParameterfv;
+RGLSYMGLGETCOLORTABLEPARAMETERIVPROC glGetColorTableParameteriv;
+RGLSYMGLBLENDEQUATIONPROC glBlendEquation;
+RGLSYMGLBLENDCOLORPROC glBlendColor;
+RGLSYMGLHISTOGRAMPROC glHistogram;
+RGLSYMGLRESETHISTOGRAMPROC glResetHistogram;
+RGLSYMGLGETHISTOGRAMPROC glGetHistogram;
+RGLSYMGLGETHISTOGRAMPARAMETERFVPROC glGetHistogramParameterfv;
+RGLSYMGLGETHISTOGRAMPARAMETERIVPROC glGetHistogramParameteriv;
+RGLSYMGLMINMAXPROC glMinmax;
+RGLSYMGLRESETMINMAXPROC glResetMinmax;
+RGLSYMGLGETMINMAXPROC glGetMinmax;
+RGLSYMGLGETMINMAXPARAMETERFVPROC glGetMinmaxParameterfv;
+RGLSYMGLGETMINMAXPARAMETERIVPROC glGetMinmaxParameteriv;
+RGLSYMGLCONVOLUTIONFILTER1DPROC glConvolutionFilter1D;
+RGLSYMGLCONVOLUTIONFILTER2DPROC glConvolutionFilter2D;
+RGLSYMGLCONVOLUTIONPARAMETERFPROC glConvolutionParameterf;
+RGLSYMGLCONVOLUTIONPARAMETERFVPROC glConvolutionParameterfv;
+RGLSYMGLCONVOLUTIONPARAMETERIPROC glConvolutionParameteri;
+RGLSYMGLCONVOLUTIONPARAMETERIVPROC glConvolutionParameteriv;
+RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC glCopyConvolutionFilter1D;
+RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC glCopyConvolutionFilter2D;
+RGLSYMGLGETCONVOLUTIONFILTERPROC glGetConvolutionFilter;
+RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC glGetConvolutionParameterfv;
+RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC glGetConvolutionParameteriv;
+RGLSYMGLSEPARABLEFILTER2DPROC glSeparableFilter2D;
+RGLSYMGLGETSEPARABLEFILTERPROC glGetSeparableFilter;
+RGLSYMGLACTIVETEXTUREPROC glActiveTexture;
+RGLSYMGLCLIENTACTIVETEXTUREPROC glClientActiveTexture;
+RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;
+RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
+RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D;
+RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D;
+RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
+RGLSYMGLMULTITEXCOORD1DPROC glMultiTexCoord1d;
+RGLSYMGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv;
+RGLSYMGLMULTITEXCOORD1FPROC glMultiTexCoord1f;
+RGLSYMGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv;
+RGLSYMGLMULTITEXCOORD1IPROC glMultiTexCoord1i;
+RGLSYMGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv;
+RGLSYMGLMULTITEXCOORD1SPROC glMultiTexCoord1s;
+RGLSYMGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv;
+RGLSYMGLMULTITEXCOORD2DPROC glMultiTexCoord2d;
+RGLSYMGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv;
+RGLSYMGLMULTITEXCOORD2FPROC glMultiTexCoord2f;
+RGLSYMGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv;
+RGLSYMGLMULTITEXCOORD2IPROC glMultiTexCoord2i;
+RGLSYMGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv;
+RGLSYMGLMULTITEXCOORD2SPROC glMultiTexCoord2s;
+RGLSYMGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv;
+RGLSYMGLMULTITEXCOORD3DPROC glMultiTexCoord3d;
+RGLSYMGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv;
+RGLSYMGLMULTITEXCOORD3FPROC glMultiTexCoord3f;
+RGLSYMGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv;
+RGLSYMGLMULTITEXCOORD3IPROC glMultiTexCoord3i;
+RGLSYMGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv;
+RGLSYMGLMULTITEXCOORD3SPROC glMultiTexCoord3s;
+RGLSYMGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv;
+RGLSYMGLMULTITEXCOORD4DPROC glMultiTexCoord4d;
+RGLSYMGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv;
+RGLSYMGLMULTITEXCOORD4FPROC glMultiTexCoord4f;
+RGLSYMGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv;
+RGLSYMGLMULTITEXCOORD4IPROC glMultiTexCoord4i;
+RGLSYMGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv;
+RGLSYMGLMULTITEXCOORD4SPROC glMultiTexCoord4s;
+RGLSYMGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv;
+RGLSYMGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd;
+RGLSYMGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf;
+RGLSYMGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd;
+RGLSYMGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf;
+RGLSYMGLSAMPLECOVERAGEPROC glSampleCoverage;
+RGLSYMGLACTIVETEXTUREARBPROC glActiveTextureARB;
+RGLSYMGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;
+RGLSYMGLMULTITEXCOORD1DARBPROC glMultiTexCoord1dARB;
+RGLSYMGLMULTITEXCOORD1DVARBPROC glMultiTexCoord1dvARB;
+RGLSYMGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB;
+RGLSYMGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fvARB;
+RGLSYMGLMULTITEXCOORD1IARBPROC glMultiTexCoord1iARB;
+RGLSYMGLMULTITEXCOORD1IVARBPROC glMultiTexCoord1ivARB;
+RGLSYMGLMULTITEXCOORD1SARBPROC glMultiTexCoord1sARB;
+RGLSYMGLMULTITEXCOORD1SVARBPROC glMultiTexCoord1svARB;
+RGLSYMGLMULTITEXCOORD2DARBPROC glMultiTexCoord2dARB;
+RGLSYMGLMULTITEXCOORD2DVARBPROC glMultiTexCoord2dvARB;
+RGLSYMGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;
+RGLSYMGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB;
+RGLSYMGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB;
+RGLSYMGLMULTITEXCOORD2IVARBPROC glMultiTexCoord2ivARB;
+RGLSYMGLMULTITEXCOORD2SARBPROC glMultiTexCoord2sARB;
+RGLSYMGLMULTITEXCOORD2SVARBPROC glMultiTexCoord2svARB;
+RGLSYMGLMULTITEXCOORD3DARBPROC glMultiTexCoord3dARB;
+RGLSYMGLMULTITEXCOORD3DVARBPROC glMultiTexCoord3dvARB;
+RGLSYMGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB;
+RGLSYMGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB;
+RGLSYMGLMULTITEXCOORD3IARBPROC glMultiTexCoord3iARB;
+RGLSYMGLMULTITEXCOORD3IVARBPROC glMultiTexCoord3ivARB;
+RGLSYMGLMULTITEXCOORD3SARBPROC glMultiTexCoord3sARB;
+RGLSYMGLMULTITEXCOORD3SVARBPROC glMultiTexCoord3svARB;
+RGLSYMGLMULTITEXCOORD4DARBPROC glMultiTexCoord4dARB;
+RGLSYMGLMULTITEXCOORD4DVARBPROC glMultiTexCoord4dvARB;
+RGLSYMGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB;
+RGLSYMGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB;
+RGLSYMGLMULTITEXCOORD4IARBPROC glMultiTexCoord4iARB;
+RGLSYMGLMULTITEXCOORD4IVARBPROC glMultiTexCoord4ivARB;
+RGLSYMGLMULTITEXCOORD4SARBPROC glMultiTexCoord4sARB;
+RGLSYMGLMULTITEXCOORD4SVARBPROC glMultiTexCoord4svARB;
+RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
+RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
+RGLSYMGLBINDTEXTURESPROC glBindTextures;
+
+#ifdef __cplusplus
+}
+#endif
+#endif // __NX_GLSYM_H__
diff --git a/deps/libretro-common/include/libchdr/bitstream.h b/deps/libretro-common/include/libchdr/bitstream.h
new file mode 100644 (file)
index 0000000..271c89c
--- /dev/null
@@ -0,0 +1,42 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    bitstream.h
+
+    Helper classes for reading/writing at the bit level.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __BITSTREAM_H__
+#define __BITSTREAM_H__
+
+#include <stdint.h>
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+/* helper class for reading from a bit buffer */
+struct bitstream
+{
+       uint32_t          buffer;       /* current bit accumulator */
+       int               bits;         /* number of bits in the accumulator */
+       const uint8_t *   read;         /* read pointer */
+       uint32_t          doffset;      /* byte offset within the data */
+       uint32_t          dlength;      /* length of the data */
+};
+
+struct bitstream*      create_bitstream(const void *src, uint32_t srclength);
+int                            bitstream_overflow(struct bitstream* bitstream);
+uint32_t                       bitstream_read_offset(struct bitstream* bitstream);
+
+uint32_t                       bitstream_read(struct bitstream* bitstream, int numbits);
+uint32_t                       bitstream_peek(struct bitstream* bitstream, int numbits);
+void                           bitstream_remove(struct bitstream* bitstream, int numbits);
+uint32_t                       bitstream_flush(struct bitstream* bitstream);
+
+#endif
diff --git a/deps/libretro-common/include/libchdr/cdrom.h b/deps/libretro-common/include/libchdr/cdrom.h
new file mode 100644 (file)
index 0000000..041ff2f
--- /dev/null
@@ -0,0 +1,69 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    cdrom.h
+
+    Generic MAME cd-rom implementation
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CDROM_H__
+#define __CDROM_H__
+
+#include <stdint.h>
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/* tracks are padded to a multiple of this many frames */
+#define CD_TRACK_PADDING        (4)
+
+#define CD_MAX_TRACKS           (99)    /* AFAIK the theoretical limit */
+#define CD_MAX_SECTOR_DATA      (2352)
+#define CD_MAX_SUBCODE_DATA     (96)
+
+#define CD_FRAME_SIZE           (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)
+#define CD_FRAMES_PER_HUNK      (8)
+
+#define CD_METADATA_WORDS       (1+(CD_MAX_TRACKS * 6))
+
+enum
+{
+       CD_TRACK_MODE1 = 0,         /* mode 1 2048 bytes/sector */
+       CD_TRACK_MODE1_RAW,         /* mode 1 2352 bytes/sector */
+       CD_TRACK_MODE2,             /* mode 2 2336 bytes/sector */
+       CD_TRACK_MODE2_FORM1,       /* mode 2 2048 bytes/sector */
+       CD_TRACK_MODE2_FORM2,       /* mode 2 2324 bytes/sector */
+       CD_TRACK_MODE2_FORM_MIX,    /* mode 2 2336 bytes/sector */
+       CD_TRACK_MODE2_RAW,         /* mode 2 2352 bytes / sector */
+       CD_TRACK_AUDIO,         /* redbook audio track 2352 bytes/sector (588 samples) */
+
+       CD_TRACK_RAW_DONTCARE       /* special flag for cdrom_read_data: just return me whatever is there */
+};
+
+enum
+{
+       CD_SUB_NORMAL = 0,          /* "cooked" 96 bytes per sector */
+       CD_SUB_RAW,                 /* raw uninterleaved 96 bytes per sector */
+       CD_SUB_NONE                 /* no subcode data stored */
+};
+
+#define CD_FLAG_GDROM   0x00000001  /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */
+#define CD_FLAG_GDROMLE 0x00000002  /* legacy GD-ROM, with little-endian CDDA data */
+
+/***************************************************************************
+    FUNCTION PROTOTYPES
+***************************************************************************/
+
+#ifdef WANT_RAW_DATA_SECTOR
+/* ECC utilities */
+int ecc_verify(const uint8_t *sector);
+void ecc_generate(uint8_t *sector);
+void ecc_clear(uint8_t *sector);
+#endif
+
+#endif  /* __CDROM_H__ */
diff --git a/deps/libretro-common/include/libchdr/chd.h b/deps/libretro-common/include/libchdr/chd.h
new file mode 100644 (file)
index 0000000..b22b6e4
--- /dev/null
@@ -0,0 +1,397 @@
+/***************************************************************************
+
+    chd.h
+
+    MAME Compressed Hunks of Data file format
+
+****************************************************************************
+
+    Copyright Aaron Giles
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+        * 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 'MAME' 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 AARON GILES ''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 AARON GILES 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.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CHD_H__
+#define __CHD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "coretypes.h"
+#include <streams/file_stream.h>
+
+/***************************************************************************
+
+    Compressed Hunks of Data header format. All numbers are stored in
+    Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2)
+    bytes long.
+
+    V1 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 hunksize;      // 512-byte sectors per hunk
+    [ 28] UINT32 totalhunks;    // total # of hunks represented
+    [ 32] UINT32 cylinders;     // number of cylinders on hard disk
+    [ 36] UINT32 heads;         // number of heads on hard disk
+    [ 40] UINT32 sectors;       // number of sectors on hard disk
+    [ 44] UINT8  md5[16];       // MD5 checksum of raw data
+    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
+    [ 76] (V1 header length)
+
+    V2 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 hunksize;      // seclen-byte sectors per hunk
+    [ 28] UINT32 totalhunks;    // total # of hunks represented
+    [ 32] UINT32 cylinders;     // number of cylinders on hard disk
+    [ 36] UINT32 heads;         // number of heads on hard disk
+    [ 40] UINT32 sectors;       // number of sectors on hard disk
+    [ 44] UINT8  md5[16];       // MD5 checksum of raw data
+    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
+    [ 76] UINT32 seclen;        // number of bytes per sector
+    [ 80] (V2 header length)
+
+    V3 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 totalhunks;    // total # of hunks represented
+    [ 28] UINT64 logicalbytes;  // logical size of the data (in bytes)
+    [ 36] UINT64 metaoffset;    // offset to the first blob of metadata
+    [ 44] UINT8  md5[16];       // MD5 checksum of raw data
+    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
+    [ 76] UINT32 hunkbytes;     // number of bytes per hunk
+    [ 80] UINT8  sha1[20];      // SHA1 checksum of raw data
+    [100] UINT8  parentsha1[20];// SHA1 checksum of parent file
+    [120] (V3 header length)
+
+    V4 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 totalhunks;    // total # of hunks represented
+    [ 28] UINT64 logicalbytes;  // logical size of the data (in bytes)
+    [ 36] UINT64 metaoffset;    // offset to the first blob of metadata
+    [ 44] UINT32 hunkbytes;     // number of bytes per hunk
+    [ 48] UINT8  sha1[20];      // combined raw+meta SHA1
+    [ 68] UINT8  parentsha1[20];// combined raw+meta SHA1 of parent
+    [ 88] UINT8  rawsha1[20];   // raw data SHA1
+    [108] (V4 header length)
+
+    Flags:
+        0x00000001 - set if this drive has a parent
+        0x00000002 - set if this drive allows writes
+
+   =========================================================================
+
+    V5 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] uint32_t length;        // length of header (including tag and length fields)
+    [ 12] uint32_t version;       // drive format version
+    [ 16] uint32_t compressors[4];// which custom compressors are used?
+    [ 32] uint64_t logicalbytes;  // logical size of the data (in bytes)
+    [ 40] uint64_t mapoffset;     // offset to the map
+    [ 48] uint64_t metaoffset;    // offset to the first blob of metadata
+    [ 56] uint32_t hunkbytes;     // number of bytes per hunk (512k maximum)
+    [ 60] uint32_t unitbytes;     // number of bytes per unit within each hunk
+    [ 64] uint8_t  rawsha1[20];   // raw data SHA1
+    [ 84] uint8_t  sha1[20];      // combined raw+meta SHA1
+    [104] uint8_t  parentsha1[20];// combined raw+meta SHA1 of parent
+    [124] (V5 header length)
+
+    If parentsha1 != 0, we have a parent (no need for flags)
+    If compressors[0] == 0, we are uncompressed (including maps)
+
+    V5 uncompressed map format:
+
+    [  0] uint32_t offset;        // starting offset / hunk size
+
+    V5 compressed map format header:
+
+    [  0] uint32_t length;        // length of compressed map
+    [  4] UINT48 datastart;     // offset of first block
+    [ 10] uint16_t crc;           // crc-16 of the map
+    [ 12] uint8_t lengthbits;     // bits used to encode complength
+    [ 13] uint8_t hunkbits;       // bits used to encode self-refs
+    [ 14] uint8_t parentunitbits; // bits used to encode parent unit refs
+    [ 15] uint8_t reserved;       // future use
+    [ 16] (compressed header length)
+
+    Each compressed map entry, once expanded, looks like:
+
+    [  0] uint8_t compression;    // compression type
+    [  1] UINT24 complength;    // compressed length
+    [  4] UINT48 offset;        // offset
+    [ 10] uint16_t crc;           // crc-16 of the data
+
+***************************************************************************/
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/* header information */
+#define CHD_HEADER_VERSION                     5
+#define CHD_V1_HEADER_SIZE                     76
+#define CHD_V2_HEADER_SIZE                     80
+#define CHD_V3_HEADER_SIZE                     120
+#define CHD_V4_HEADER_SIZE                     108
+#define CHD_V5_HEADER_SIZE          124
+
+#define CHD_MAX_HEADER_SIZE                    CHD_V5_HEADER_SIZE
+
+/* checksumming information */
+#define CHD_MD5_BYTES                          16
+#define CHD_SHA1_BYTES                         20
+
+/* CHD global flags */
+#define CHDFLAGS_HAS_PARENT                    0x00000001
+#define CHDFLAGS_IS_WRITEABLE          0x00000002
+#define CHDFLAGS_UNDEFINED                     0xfffffffc
+
+#define CHD_MAKE_TAG(a,b,c,d)       (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+/* compression types */
+#define CHDCOMPRESSION_NONE                    0
+#define CHDCOMPRESSION_ZLIB                    1
+#define CHDCOMPRESSION_ZLIB_PLUS       2
+#define CHDCOMPRESSION_AV                      3
+
+#define CHD_CODEC_ZLIB                         CHD_MAKE_TAG('z','l','i','b')
+
+/* general codecs with CD frontend */
+#define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l')
+#define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z')
+#define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l')
+
+/* A/V codec configuration parameters */
+#define AV_CODEC_COMPRESS_CONFIG       1
+#define AV_CODEC_DECOMPRESS_CONFIG     2
+
+/* metadata parameters */
+#define CHDMETATAG_WILDCARD                    0
+#define CHD_METAINDEX_APPEND           ((UINT32)-1)
+
+/* metadata flags */
+#define CHD_MDFLAGS_CHECKSUM           0x01            /* indicates data is checksummed */
+
+/* standard hard disk metadata */
+#define HARD_DISK_METADATA_TAG         CHD_MAKE_TAG('G','D','D','D')
+#define HARD_DISK_METADATA_FORMAT      "CYLS:%u,HEADS:%u,SECS:%u,BPS:%u"
+
+/* hard disk identify information */
+#define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T')
+
+/* hard disk key information */
+#define HARD_DISK_KEY_METADATA_TAG     CHD_MAKE_TAG('K','E','Y',' ')
+
+/* pcmcia CIS information */
+#define PCMCIA_CIS_METADATA_TAG                CHD_MAKE_TAG('C','I','S',' ')
+
+/* standard CD-ROM metadata */
+#define CDROM_OLD_METADATA_TAG         CHD_MAKE_TAG('C','H','C','D')
+#define CDROM_TRACK_METADATA_TAG          CHD_MAKE_TAG('C','H','T','R')
+#define CDROM_TRACK_METADATA_FORMAT    "TRACK:%u TYPE:%s SUBTYPE:%s FRAMES:%u"
+#define CDROM_TRACK_METADATA2_TAG      CHD_MAKE_TAG('C','H','T','2')
+#define CDROM_TRACK_METADATA2_FORMAT   "TRACK:%u TYPE:%s SUBTYPE:%s FRAMES:%u PREGAP:%u PGTYPE:%s PGSUB:%s POSTGAP:%u"
+#define GDROM_OLD_METADATA_TAG         CHD_MAKE_TAG('C','H','G','T')
+#define GDROM_TRACK_METADATA_TAG       CHD_MAKE_TAG('C', 'H', 'G', 'D')
+#define GDROM_TRACK_METADATA_FORMAT    "TRACK:%u TYPE:%s SUBTYPE:%s FRAMES:%u PAD:%u PREGAP:%u PGTYPE:%s PGSUB:%s POSTGAP:%u"
+
+/* standard A/V metadata */
+#define AV_METADATA_TAG                                CHD_MAKE_TAG('A','V','A','V')
+#define AV_METADATA_FORMAT                     "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"
+
+/* A/V laserdisc frame metadata */
+#define AV_LD_METADATA_TAG                     CHD_MAKE_TAG('A','V','L','D')
+
+/* CHD open values */
+#define CHD_OPEN_READ                          1
+#define CHD_OPEN_READWRITE                     2
+
+/* error types */
+enum _chd_error
+{
+       CHDERR_NONE,
+       CHDERR_NO_INTERFACE,
+       CHDERR_OUT_OF_MEMORY,
+       CHDERR_INVALID_FILE,
+       CHDERR_INVALID_PARAMETER,
+       CHDERR_INVALID_DATA,
+       CHDERR_FILE_NOT_FOUND,
+       CHDERR_REQUIRES_PARENT,
+       CHDERR_FILE_NOT_WRITEABLE,
+       CHDERR_READ_ERROR,
+       CHDERR_WRITE_ERROR,
+       CHDERR_CODEC_ERROR,
+       CHDERR_INVALID_PARENT,
+       CHDERR_HUNK_OUT_OF_RANGE,
+       CHDERR_DECOMPRESSION_ERROR,
+       CHDERR_COMPRESSION_ERROR,
+       CHDERR_CANT_CREATE_FILE,
+       CHDERR_CANT_VERIFY,
+       CHDERR_NOT_SUPPORTED,
+       CHDERR_METADATA_NOT_FOUND,
+       CHDERR_INVALID_METADATA_SIZE,
+       CHDERR_UNSUPPORTED_VERSION,
+       CHDERR_VERIFY_INCOMPLETE,
+       CHDERR_INVALID_METADATA,
+       CHDERR_INVALID_STATE,
+       CHDERR_OPERATION_PENDING,
+       CHDERR_NO_ASYNC_OPERATION,
+       CHDERR_UNSUPPORTED_FORMAT
+};
+typedef enum _chd_error chd_error;
+
+/***************************************************************************
+    TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque types */
+typedef struct _chd_file chd_file;
+
+/* extract header structure (NOT the on-disk header structure) */
+typedef struct _chd_header chd_header;
+struct _chd_header
+{
+       UINT32          length;                                         /* length of header data */
+       UINT32          version;                                        /* drive format version */
+       UINT32          flags;                                          /* flags field */
+       UINT32          compression[4];                         /* compression type */
+       UINT32          hunkbytes;                                      /* number of bytes per hunk */
+       UINT32          totalhunks;                                     /* total # of hunks represented */
+       UINT64          logicalbytes;                           /* logical size of the data */
+       UINT64          metaoffset;                                     /* offset in file of first metadata */
+       UINT64          mapoffset;                                      /* TOOD V5 */
+       UINT8           md5[CHD_MD5_BYTES];                     /* overall MD5 checksum */
+       UINT8           parentmd5[CHD_MD5_BYTES];       /* overall MD5 checksum of parent */
+       UINT8           sha1[CHD_SHA1_BYTES];           /* overall SHA1 checksum */
+       UINT8           rawsha1[CHD_SHA1_BYTES];        /* SHA1 checksum of raw data */
+       UINT8           parentsha1[CHD_SHA1_BYTES];     /* overall SHA1 checksum of parent */
+       UINT32          unitbytes;                                      /* TODO V5 */
+       UINT64          unitcount;                                      /* TODO V5 */
+    UINT32      hunkcount;                  /* TODO V5 */
+
+    /* map information */
+    UINT32      mapentrybytes;              /* length of each entry in a map (V5) */
+    UINT8*      rawmap;                     /* raw map data */
+
+       UINT32          obsolete_cylinders;                     /* obsolete field -- do not use! */
+       UINT32          obsolete_sectors;                       /* obsolete field -- do not use! */
+       UINT32          obsolete_heads;                         /* obsolete field -- do not use! */
+       UINT32          obsolete_hunksize;                      /* obsolete field -- do not use! */
+};
+
+/* structure for returning information about a verification pass */
+typedef struct _chd_verify_result chd_verify_result;
+struct _chd_verify_result
+{
+       UINT8           md5[CHD_MD5_BYTES];                     /* overall MD5 checksum */
+       UINT8           sha1[CHD_SHA1_BYTES];           /* overall SHA1 checksum */
+       UINT8           rawsha1[CHD_SHA1_BYTES];        /* SHA1 checksum of raw data */
+       UINT8           metasha1[CHD_SHA1_BYTES];       /* SHA1 checksum of metadata */
+};
+
+/***************************************************************************
+    FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* ----- CHD file management ----- */
+
+/* create a new CHD file fitting the given description */
+/* chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */
+
+/* same as chd_create(), but accepts an already-opened core_file object */
+/* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */
+
+/* open an existing CHD file */
+chd_error chd_open_file(RFILE *file, int mode, chd_file *parent, chd_file **chd);
+
+chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);
+
+/* precache underlying file */
+chd_error chd_precache(chd_file *chd);
+
+/* close a CHD file */
+void chd_close(chd_file *chd);
+
+/* return the associated core_file */
+RFILE *chd_core_file(chd_file *chd);
+
+/* return an error string for the given CHD error */
+const char *chd_error_string(chd_error err);
+
+/* ----- CHD header management ----- */
+
+/* return a pointer to the extracted CHD header data */
+const chd_header *chd_get_header(chd_file *chd);
+
+/* ----- core data read/write ----- */
+
+/* read one hunk from the CHD file */
+chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer);
+
+/* ----- metadata management ----- */
+
+/* get indexed metadata of a particular sort */
+chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags);
+
+/* ----- codec interfaces ----- */
+
+/* set internal codec parameters */
+chd_error chd_codec_config(chd_file *chd, int param, void *config);
+
+/* return a string description of a codec */
+const char *chd_get_codec_name(UINT32 codec);
+
+extern const uint8_t s_cd_sync_header[12];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CHD_H__ */
diff --git a/deps/libretro-common/include/libchdr/coretypes.h b/deps/libretro-common/include/libchdr/coretypes.h
new file mode 100644 (file)
index 0000000..2a68a8a
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __CORETYPES_H__
+#define __CORETYPES_H__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <retro_miscellaneous.h>
+
+typedef uint64_t UINT64;
+#ifndef OSD_CPU_H
+typedef uint32_t UINT32;
+typedef uint16_t UINT16;
+typedef uint8_t UINT8;
+#endif
+
+typedef int64_t INT64;
+#ifndef OSD_CPU_H
+typedef int32_t INT32;
+typedef int16_t INT16;
+typedef int8_t INT8;
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/libchdr/flac.h b/deps/libretro-common/include/libchdr/flac.h
new file mode 100644 (file)
index 0000000..2ce112d
--- /dev/null
@@ -0,0 +1,70 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    flac.h
+
+    FLAC compression wrappers
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __FLAC_H__
+#define __FLAC_H__
+
+#include <stdint.h>
+#include "libchdr_zlib.h"
+#include "FLAC/ordinals.h"
+#include "FLAC/stream_decoder.h"
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+typedef struct _flac_decoder flac_decoder;
+struct _flac_decoder {
+               /* output state */
+       FLAC__StreamDecoder*    decoder;                                /* actual encoder */
+       uint32_t                sample_rate;                    /* decoded sample rate */
+       uint8_t                 channels;                               /* decoded number of channels */
+       uint8_t                 bits_per_sample;                /* decoded bits per sample */
+       uint32_t                compressed_offset;              /* current offset in compressed data */
+       const FLAC__byte *      compressed_start;               /* start of compressed data */
+       uint32_t                compressed_length;              /* length of compressed data */
+       const FLAC__byte *      compressed2_start;              /* start of compressed data */
+       uint32_t                compressed2_length;             /* length of compressed data */
+       int16_t *               uncompressed_start[8];  /* pointer to start of uncompressed data (up to 8 streams) */
+       uint32_t                uncompressed_offset;    /* current position in uncompressed data */
+       uint32_t                uncompressed_length;    /* length of uncompressed data */
+       int                     uncompressed_swap;              /* swap uncompressed sample data */
+       uint8_t                 custom_header[0x2a];    /* custom header */
+};
+
+/* ======================> flac_decoder */
+
+void           flac_decoder_init(flac_decoder* decoder);
+void           flac_decoder_free(flac_decoder* decoder);
+int            flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);
+int            flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);
+uint32_t       flac_decoder_finish(flac_decoder* decoder);
+
+/* codec-private data for the CDFL codec */
+typedef struct _cdfl_codec_data cdfl_codec_data;
+struct _cdfl_codec_data {
+       /* internal state */
+       int             swap_endian;
+       flac_decoder    decoder;
+#ifdef WANT_SUBCODE
+       zlib_codec_data         subcode_decompressor;
+#endif
+       uint8_t*        buffer;
+};
+
+/* cdfl compression codec */
+chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
+void cdfl_codec_free(void* codec);
+chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+#endif /* __FLAC_H__ */
diff --git a/deps/libretro-common/include/libchdr/huffman.h b/deps/libretro-common/include/libchdr/huffman.h
new file mode 100644 (file)
index 0000000..ec5ef54
--- /dev/null
@@ -0,0 +1,89 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    huffman.h
+
+    Static Huffman compression and decompression helpers.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __HUFFMAN_H__
+#define __HUFFMAN_H__
+
+#include "bitstream.h"
+
+/***************************************************************************
+ *  CONSTANTS
+ ***************************************************************************
+ */
+
+enum huffman_error
+{
+       HUFFERR_NONE = 0,
+       HUFFERR_TOO_MANY_BITS,
+       HUFFERR_INVALID_DATA,
+       HUFFERR_INPUT_BUFFER_TOO_SMALL,
+       HUFFERR_OUTPUT_BUFFER_TOO_SMALL,
+       HUFFERR_INTERNAL_INCONSISTENCY,
+       HUFFERR_TOO_MANY_CONTEXTS
+};
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+typedef uint16_t lookup_value;
+
+/* a node in the huffman tree */
+struct node_t
+{
+       struct node_t*          parent;         /* pointer to parent node */
+       uint32_t                        count;          /* number of hits on this node */
+       uint32_t                        weight;         /* assigned weight of this node */
+       uint32_t                        bits;           /* bits used to encode the node */
+       uint8_t                         numbits;        /* number of bits needed for this node */
+};
+
+/* ======================> huffman_context_base */
+
+/* context class for decoding */
+struct huffman_decoder
+{
+       /* internal state */
+       uint32_t                        numcodes;             /* number of total codes being processed */
+       uint8_t                         maxbits;           /* maximum bits per code */
+       uint8_t                         prevdata;             /* value of the previous data (for delta-RLE encoding) */
+       int                     rleremaining;         /* number of RLE bytes remaining (for delta-RLE encoding) */
+       lookup_value *          lookup;               /* pointer to the lookup table */
+       struct node_t *     huffnode;             /* array of nodes */
+       uint32_t *              datahisto;            /* histogram of data values */
+
+       /* array versions of the info we need */
+#if 0
+       node_t*                 huffnode_array; /* [_NumCodes]; */
+       lookup_value*   lookup_array; /* [1 << _MaxBits]; */
+#endif
+};
+
+/* ======================> huffman_decoder */
+
+struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);
+void delete_huffman_decoder(struct huffman_decoder* decoder);
+
+/* single item operations */
+uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+
+enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+
+int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight);
+enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder);
+enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder);
+
+void huffman_build_lookup_table(struct huffman_decoder* decoder);
+
+#endif
diff --git a/deps/libretro-common/include/libchdr/libchdr_zlib.h b/deps/libretro-common/include/libchdr/libchdr_zlib.h
new file mode 100644 (file)
index 0000000..86544d6
--- /dev/null
@@ -0,0 +1,69 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    libchr_zlib.h
+
+    Zlib compression wrappers
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __LIBCHDR_ZLIB_H__
+#define __LIBCHDR_ZLIB_H__
+
+#include <stdint.h>
+
+#include <zlib.h>
+#include "coretypes.h"
+#include "chd.h"
+
+#define MAX_ZLIB_ALLOCS                                64
+
+/* codec-private data for the ZLIB codec */
+
+typedef struct _zlib_allocator zlib_allocator;
+struct _zlib_allocator
+{
+       UINT32 *                                allocptr[MAX_ZLIB_ALLOCS];
+       UINT32 *                                allocptr2[MAX_ZLIB_ALLOCS];
+};
+
+typedef struct _zlib_codec_data zlib_codec_data;
+struct _zlib_codec_data
+{
+       z_stream                                inflater;
+       zlib_allocator                  allocator;
+};
+
+/* codec-private data for the CDZL codec */
+typedef struct _cdzl_codec_data cdzl_codec_data;
+struct _cdzl_codec_data {
+       /* internal state */
+       zlib_codec_data         base_decompressor;
+#ifdef WANT_SUBCODE
+       zlib_codec_data         subcode_decompressor;
+#endif
+       uint8_t*                        buffer;
+};
+
+/* zlib compression codec */
+chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
+
+void zlib_codec_free(void *codec);
+
+chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
+
+void zlib_fast_free(voidpf opaque, voidpf address);
+
+/* cdzl compression codec */
+chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);
+
+void cdzl_codec_free(void* codec);
+
+chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+#endif /* __LIBCHDR_ZLIB_H__ */
diff --git a/deps/libretro-common/include/libchdr/lzma.h b/deps/libretro-common/include/libchdr/lzma.h
new file mode 100644 (file)
index 0000000..15deb62
--- /dev/null
@@ -0,0 +1,73 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    lzma.h
+
+    LZMA compression wrappers
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __LIBCHDR_LZMA_H__
+#define __LIBCHDR_LZMA_H__
+
+#include <stdint.h>
+
+#include <LzmaEnc.h>
+#include <LzmaDec.h>
+
+#include <libchdr/libchdr_zlib.h>
+
+/* codec-private data for the LZMA codec */
+#define MAX_LZMA_ALLOCS 64
+
+typedef struct _lzma_allocator lzma_allocator;
+struct _lzma_allocator
+{
+       void *(*Alloc)(void *p, size_t size);
+       void (*Free)(void *p, void *address); /* address can be 0 */
+       void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
+       uint32_t*       allocptr[MAX_LZMA_ALLOCS];
+       uint32_t*       allocptr2[MAX_LZMA_ALLOCS];
+};
+
+typedef struct _lzma_codec_data lzma_codec_data;
+struct _lzma_codec_data
+{
+       CLzmaDec                decoder;
+       lzma_allocator  allocator;
+};
+
+/* codec-private data for the CDLZ codec */
+typedef struct _cdlz_codec_data cdlz_codec_data;
+struct _cdlz_codec_data {
+       /* internal state */
+       lzma_codec_data         base_decompressor;
+#ifdef WANT_SUBCODE
+       zlib_codec_data         subcode_decompressor;
+#endif
+       uint8_t*                        buffer;
+};
+
+chd_error lzma_codec_init(void* codec, uint32_t hunkbytes);
+
+void lzma_codec_free(void* codec);
+
+/*-------------------------------------------------
+ *  decompress - decompress data using the LZMA
+ *  codec
+ *-------------------------------------------------
+ */
+
+chd_error lzma_codec_decompress(void* codec, const uint8_t *src,
+      uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);
+
+void cdlz_codec_free(void* codec);
+
+chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+#endif /* __LIBCHDR_LZMA_H__ */
diff --git a/deps/libretro-common/include/libchdr/minmax.h b/deps/libretro-common/include/libchdr/minmax.h
new file mode 100644 (file)
index 0000000..0be41f3
--- /dev/null
@@ -0,0 +1,21 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    minmax.h
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __MINMAX_H__
+#define __MINMAX_H__
+
+#if defined(RARCH_INTERNAL) || defined(__LIBRETRO__)
+#include <retro_miscellaneous.h>
+#else
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/libco.h b/deps/libretro-common/include/libco.h
new file mode 100644 (file)
index 0000000..177721a
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (libco.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBCO_H
+#define LIBCO_H
+
+#include <retro_common_api.h>
+
+#ifdef LIBCO_C
+  #ifdef LIBCO_MP
+    #define thread_local __thread
+  #else
+    #define thread_local
+  #endif
+#endif
+
+RETRO_BEGIN_DECLS
+
+typedef void* cothread_t;
+
+/**
+ * co_active:
+ *
+ * Gets the currently active context.
+ *
+ * Returns: active context.
+ **/
+cothread_t co_active(void);
+
+/**
+ * co_create:
+ * @int                : stack size
+ * @funcptr            : thread entry function callback
+ *
+ * Create a co_thread.
+ *
+ * Returns: cothread if successful, otherwise NULL.
+ */
+cothread_t co_create(unsigned int, void (*)(void));
+
+/**
+ * co_delete:
+ * @cothread           : cothread object
+ *
+ * Frees a co_thread.
+ */
+void co_delete(cothread_t cothread);
+
+/**
+ * co_switch:
+ * @cothread           : cothread object to switch to
+ *
+ * Do a context switch to @cothread.
+ */
+void co_switch(cothread_t cothread);
+
+RETRO_END_DECLS
+
+/* ifndef LIBCO_H */
+#endif
diff --git a/deps/libretro-common/include/libretro.h b/deps/libretro-common/include/libretro.h
new file mode 100644 (file)
index 0000000..a08b69c
--- /dev/null
@@ -0,0 +1,4190 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro API header (libretro.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_H__
+#define LIBRETRO_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __cplusplus
+#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
+/* Hack applied for MSVC when compiling in C89 mode
+ * as it isn't C99-compliant. */
+#define bool unsigned char
+#define true 1
+#define false 0
+#else
+#include <stdbool.h>
+#endif
+#endif
+
+#ifndef RETRO_CALLCONV
+#  if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__)
+#    define RETRO_CALLCONV __attribute__((cdecl))
+#  elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64)
+#    define RETRO_CALLCONV __cdecl
+#  else
+#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */
+#  endif
+#endif
+
+#ifndef RETRO_API
+#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+#    ifdef RETRO_IMPORT_SYMBOLS
+#      ifdef __GNUC__
+#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))
+#      else
+#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)
+#      endif
+#    else
+#      ifdef __GNUC__
+#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))
+#      else
+#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)
+#      endif
+#    endif
+#  else
+#      if defined(__GNUC__) && __GNUC__ >= 4
+#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
+#      else
+#        define RETRO_API RETRO_CALLCONV
+#      endif
+#  endif
+#endif
+
+/* Used for checking API/ABI mismatches that can break libretro
+ * implementations.
+ * It is not incremented for compatible changes to the API.
+ */
+#define RETRO_API_VERSION         1
+
+/*
+ * Libretro's fundamental device abstractions.
+ *
+ * Libretro's input system consists of some standardized device types,
+ * such as a joypad (with/without analog), mouse, keyboard, lightgun
+ * and a pointer.
+ *
+ * The functionality of these devices are fixed, and individual cores
+ * map their own concept of a controller to libretro's abstractions.
+ * This makes it possible for frontends to map the abstract types to a
+ * real input device, and not having to worry about binding input
+ * correctly to arbitrary controller layouts.
+ */
+
+#define RETRO_DEVICE_TYPE_SHIFT         8
+#define RETRO_DEVICE_MASK               ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)
+#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)
+
+/* Input disabled. */
+#define RETRO_DEVICE_NONE         0
+
+/* The JOYPAD is called RetroPad. It is essentially a Super Nintendo
+ * controller, but with additional L2/R2/L3/R3 buttons, similar to a
+ * PS1 DualShock. */
+#define RETRO_DEVICE_JOYPAD       1
+
+/* The mouse is a simple mouse, similar to Super Nintendo's mouse.
+ * X and Y coordinates are reported relatively to last poll (poll callback).
+ * It is up to the libretro implementation to keep track of where the mouse
+ * pointer is supposed to be on the screen.
+ * The frontend must make sure not to interfere with its own hardware
+ * mouse pointer.
+ */
+#define RETRO_DEVICE_MOUSE        2
+
+/* KEYBOARD device lets one poll for raw key pressed.
+ * It is poll based, so input callback will return with the current
+ * pressed state.
+ * For event/text based keyboard input, see
+ * RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
+ */
+#define RETRO_DEVICE_KEYBOARD     3
+
+/* LIGHTGUN device is similar to Guncon-2 for PlayStation 2.
+ * It reports X/Y coordinates in screen space (similar to the pointer)
+ * in the range [-0x8000, 0x7fff] in both axes, with zero being center and
+ * -0x8000 being out of bounds.
+ * As well as reporting on/off screen state. It features a trigger,
+ * start/select buttons, auxiliary action buttons and a
+ * directional pad. A forced off-screen shot can be requested for
+ * auto-reloading function in some games.
+ */
+#define RETRO_DEVICE_LIGHTGUN     4
+
+/* The ANALOG device is an extension to JOYPAD (RetroPad).
+ * Similar to DualShock2 it adds two analog sticks and all buttons can
+ * be analog. This is treated as a separate device type as it returns
+ * axis values in the full analog range of [-0x7fff, 0x7fff],
+ * although some devices may return -0x8000.
+ * Positive X axis is right. Positive Y axis is down.
+ * Buttons are returned in the range [0, 0x7fff].
+ * Only use ANALOG type when polling for analog values.
+ */
+#define RETRO_DEVICE_ANALOG       5
+
+/* Abstracts the concept of a pointing mechanism, e.g. touch.
+ * This allows libretro to query in absolute coordinates where on the
+ * screen a mouse (or something similar) is being placed.
+ * For a touch centric device, coordinates reported are the coordinates
+ * of the press.
+ *
+ * Coordinates in X and Y are reported as:
+ * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
+ * and 0x7fff corresponds to the far right/bottom of the screen.
+ * The "screen" is here defined as area that is passed to the frontend and
+ * later displayed on the monitor.
+ *
+ * The frontend is free to scale/resize this screen as it sees fit, however,
+ * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
+ * game image, etc.
+ *
+ * To check if the pointer coordinates are valid (e.g. a touch display
+ * actually being touched), PRESSED returns 1 or 0.
+ *
+ * If using a mouse on a desktop, PRESSED will usually correspond to the
+ * left mouse button, but this is a frontend decision.
+ * PRESSED will only return 1 if the pointer is inside the game screen.
+ *
+ * For multi-touch, the index variable can be used to successively query
+ * more presses.
+ * If index = 0 returns true for _PRESSED, coordinates can be extracted
+ * with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with
+ * index = 1, and so on.
+ * Eventually _PRESSED will return false for an index. No further presses
+ * are registered at this point. */
+#define RETRO_DEVICE_POINTER      6
+
+/* Buttons for the RetroPad (JOYPAD).
+ * The placement of these is equivalent to placements on the
+ * Super Nintendo controller.
+ * L2/R2/L3/R3 buttons correspond to the PS1 DualShock.
+ * Also used as id values for RETRO_DEVICE_INDEX_ANALOG_BUTTON */
+#define RETRO_DEVICE_ID_JOYPAD_B        0
+#define RETRO_DEVICE_ID_JOYPAD_Y        1
+#define RETRO_DEVICE_ID_JOYPAD_SELECT   2
+#define RETRO_DEVICE_ID_JOYPAD_START    3
+#define RETRO_DEVICE_ID_JOYPAD_UP       4
+#define RETRO_DEVICE_ID_JOYPAD_DOWN     5
+#define RETRO_DEVICE_ID_JOYPAD_LEFT     6
+#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7
+#define RETRO_DEVICE_ID_JOYPAD_A        8
+#define RETRO_DEVICE_ID_JOYPAD_X        9
+#define RETRO_DEVICE_ID_JOYPAD_L       10
+#define RETRO_DEVICE_ID_JOYPAD_R       11
+#define RETRO_DEVICE_ID_JOYPAD_L2      12
+#define RETRO_DEVICE_ID_JOYPAD_R2      13
+#define RETRO_DEVICE_ID_JOYPAD_L3      14
+#define RETRO_DEVICE_ID_JOYPAD_R3      15
+
+#define RETRO_DEVICE_ID_JOYPAD_MASK    256
+
+/* Index / Id values for ANALOG device. */
+#define RETRO_DEVICE_INDEX_ANALOG_LEFT       0
+#define RETRO_DEVICE_INDEX_ANALOG_RIGHT      1
+#define RETRO_DEVICE_INDEX_ANALOG_BUTTON     2
+#define RETRO_DEVICE_ID_ANALOG_X             0
+#define RETRO_DEVICE_ID_ANALOG_Y             1
+
+/* Id values for MOUSE. */
+#define RETRO_DEVICE_ID_MOUSE_X                0
+#define RETRO_DEVICE_ID_MOUSE_Y                1
+#define RETRO_DEVICE_ID_MOUSE_LEFT             2
+#define RETRO_DEVICE_ID_MOUSE_RIGHT            3
+#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4
+#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5
+#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6
+#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7
+#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8
+#define RETRO_DEVICE_ID_MOUSE_BUTTON_4         9
+#define RETRO_DEVICE_ID_MOUSE_BUTTON_5         10
+
+/* Id values for LIGHTGUN. */
+#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X        13 /*Absolute Position*/
+#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y        14 /*Absolute*/
+#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN    15 /*Status Check*/
+#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER          2
+#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD          16 /*Forced off-screen shot*/
+#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A            3
+#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B            4
+#define RETRO_DEVICE_ID_LIGHTGUN_START            6
+#define RETRO_DEVICE_ID_LIGHTGUN_SELECT           7
+#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C            8
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP          9
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN       10
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT       11
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT      12
+/* deprecated */
+#define RETRO_DEVICE_ID_LIGHTGUN_X                0 /*Relative Position*/
+#define RETRO_DEVICE_ID_LIGHTGUN_Y                1 /*Relative*/
+#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR           3 /*Use Aux:A*/
+#define RETRO_DEVICE_ID_LIGHTGUN_TURBO            4 /*Use Aux:B*/
+#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE            5 /*Use Start*/
+
+/* Id values for POINTER. */
+#define RETRO_DEVICE_ID_POINTER_X         0
+#define RETRO_DEVICE_ID_POINTER_Y         1
+#define RETRO_DEVICE_ID_POINTER_PRESSED   2
+#define RETRO_DEVICE_ID_POINTER_COUNT     3
+
+/* Returned from retro_get_region(). */
+#define RETRO_REGION_NTSC  0
+#define RETRO_REGION_PAL   1
+
+/* Id values for LANGUAGE */
+enum retro_language
+{
+   RETRO_LANGUAGE_ENGLISH             = 0,
+   RETRO_LANGUAGE_JAPANESE            = 1,
+   RETRO_LANGUAGE_FRENCH              = 2,
+   RETRO_LANGUAGE_SPANISH             = 3,
+   RETRO_LANGUAGE_GERMAN              = 4,
+   RETRO_LANGUAGE_ITALIAN             = 5,
+   RETRO_LANGUAGE_DUTCH               = 6,
+   RETRO_LANGUAGE_PORTUGUESE_BRAZIL   = 7,
+   RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,
+   RETRO_LANGUAGE_RUSSIAN             = 9,
+   RETRO_LANGUAGE_KOREAN              = 10,
+   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,
+   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 12,
+   RETRO_LANGUAGE_ESPERANTO           = 13,
+   RETRO_LANGUAGE_POLISH              = 14,
+   RETRO_LANGUAGE_VIETNAMESE          = 15,
+   RETRO_LANGUAGE_ARABIC              = 16,
+   RETRO_LANGUAGE_GREEK               = 17,
+   RETRO_LANGUAGE_TURKISH             = 18,
+   RETRO_LANGUAGE_SLOVAK              = 19,
+   RETRO_LANGUAGE_PERSIAN             = 20,
+   RETRO_LANGUAGE_HEBREW              = 21,
+   RETRO_LANGUAGE_ASTURIAN            = 22,
+   RETRO_LANGUAGE_FINNISH             = 23,
+   RETRO_LANGUAGE_INDONESIAN          = 24,
+   RETRO_LANGUAGE_SWEDISH             = 25,
+   RETRO_LANGUAGE_UKRAINIAN           = 26,
+   RETRO_LANGUAGE_CZECH               = 27,
+   RETRO_LANGUAGE_CATALAN_VALENCIA    = 28,
+   RETRO_LANGUAGE_CATALAN             = 29,
+   RETRO_LANGUAGE_BRITISH_ENGLISH     = 30,
+   RETRO_LANGUAGE_HUNGARIAN           = 31,
+   RETRO_LANGUAGE_LAST,
+
+   /* Ensure sizeof(enum) == sizeof(int) */
+   RETRO_LANGUAGE_DUMMY          = INT_MAX
+};
+
+/* Passed to retro_get_memory_data/size().
+ * If the memory type doesn't apply to the
+ * implementation NULL/0 can be returned.
+ */
+#define RETRO_MEMORY_MASK        0xff
+
+/* Regular save RAM. This RAM is usually found on a game cartridge,
+ * backed up by a battery.
+ * If save game data is too complex for a single memory buffer,
+ * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
+ * callback can be used. */
+#define RETRO_MEMORY_SAVE_RAM    0
+
+/* Some games have a built-in clock to keep track of time.
+ * This memory is usually just a couple of bytes to keep track of time.
+ */
+#define RETRO_MEMORY_RTC         1
+
+/* System ram lets a frontend peek into a game systems main RAM. */
+#define RETRO_MEMORY_SYSTEM_RAM  2
+
+/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
+#define RETRO_MEMORY_VIDEO_RAM   3
+
+/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
+enum retro_key
+{
+   RETROK_UNKNOWN        = 0,
+   RETROK_FIRST          = 0,
+   RETROK_BACKSPACE      = 8,
+   RETROK_TAB            = 9,
+   RETROK_CLEAR          = 12,
+   RETROK_RETURN         = 13,
+   RETROK_PAUSE          = 19,
+   RETROK_ESCAPE         = 27,
+   RETROK_SPACE          = 32,
+   RETROK_EXCLAIM        = 33,
+   RETROK_QUOTEDBL       = 34,
+   RETROK_HASH           = 35,
+   RETROK_DOLLAR         = 36,
+   RETROK_AMPERSAND      = 38,
+   RETROK_QUOTE          = 39,
+   RETROK_LEFTPAREN      = 40,
+   RETROK_RIGHTPAREN     = 41,
+   RETROK_ASTERISK       = 42,
+   RETROK_PLUS           = 43,
+   RETROK_COMMA          = 44,
+   RETROK_MINUS          = 45,
+   RETROK_PERIOD         = 46,
+   RETROK_SLASH          = 47,
+   RETROK_0              = 48,
+   RETROK_1              = 49,
+   RETROK_2              = 50,
+   RETROK_3              = 51,
+   RETROK_4              = 52,
+   RETROK_5              = 53,
+   RETROK_6              = 54,
+   RETROK_7              = 55,
+   RETROK_8              = 56,
+   RETROK_9              = 57,
+   RETROK_COLON          = 58,
+   RETROK_SEMICOLON      = 59,
+   RETROK_LESS           = 60,
+   RETROK_EQUALS         = 61,
+   RETROK_GREATER        = 62,
+   RETROK_QUESTION       = 63,
+   RETROK_AT             = 64,
+   RETROK_LEFTBRACKET    = 91,
+   RETROK_BACKSLASH      = 92,
+   RETROK_RIGHTBRACKET   = 93,
+   RETROK_CARET          = 94,
+   RETROK_UNDERSCORE     = 95,
+   RETROK_BACKQUOTE      = 96,
+   RETROK_a              = 97,
+   RETROK_b              = 98,
+   RETROK_c              = 99,
+   RETROK_d              = 100,
+   RETROK_e              = 101,
+   RETROK_f              = 102,
+   RETROK_g              = 103,
+   RETROK_h              = 104,
+   RETROK_i              = 105,
+   RETROK_j              = 106,
+   RETROK_k              = 107,
+   RETROK_l              = 108,
+   RETROK_m              = 109,
+   RETROK_n              = 110,
+   RETROK_o              = 111,
+   RETROK_p              = 112,
+   RETROK_q              = 113,
+   RETROK_r              = 114,
+   RETROK_s              = 115,
+   RETROK_t              = 116,
+   RETROK_u              = 117,
+   RETROK_v              = 118,
+   RETROK_w              = 119,
+   RETROK_x              = 120,
+   RETROK_y              = 121,
+   RETROK_z              = 122,
+   RETROK_LEFTBRACE      = 123,
+   RETROK_BAR            = 124,
+   RETROK_RIGHTBRACE     = 125,
+   RETROK_TILDE          = 126,
+   RETROK_DELETE         = 127,
+
+   RETROK_KP0            = 256,
+   RETROK_KP1            = 257,
+   RETROK_KP2            = 258,
+   RETROK_KP3            = 259,
+   RETROK_KP4            = 260,
+   RETROK_KP5            = 261,
+   RETROK_KP6            = 262,
+   RETROK_KP7            = 263,
+   RETROK_KP8            = 264,
+   RETROK_KP9            = 265,
+   RETROK_KP_PERIOD      = 266,
+   RETROK_KP_DIVIDE      = 267,
+   RETROK_KP_MULTIPLY    = 268,
+   RETROK_KP_MINUS       = 269,
+   RETROK_KP_PLUS        = 270,
+   RETROK_KP_ENTER       = 271,
+   RETROK_KP_EQUALS      = 272,
+
+   RETROK_UP             = 273,
+   RETROK_DOWN           = 274,
+   RETROK_RIGHT          = 275,
+   RETROK_LEFT           = 276,
+   RETROK_INSERT         = 277,
+   RETROK_HOME           = 278,
+   RETROK_END            = 279,
+   RETROK_PAGEUP         = 280,
+   RETROK_PAGEDOWN       = 281,
+
+   RETROK_F1             = 282,
+   RETROK_F2             = 283,
+   RETROK_F3             = 284,
+   RETROK_F4             = 285,
+   RETROK_F5             = 286,
+   RETROK_F6             = 287,
+   RETROK_F7             = 288,
+   RETROK_F8             = 289,
+   RETROK_F9             = 290,
+   RETROK_F10            = 291,
+   RETROK_F11            = 292,
+   RETROK_F12            = 293,
+   RETROK_F13            = 294,
+   RETROK_F14            = 295,
+   RETROK_F15            = 296,
+
+   RETROK_NUMLOCK        = 300,
+   RETROK_CAPSLOCK       = 301,
+   RETROK_SCROLLOCK      = 302,
+   RETROK_RSHIFT         = 303,
+   RETROK_LSHIFT         = 304,
+   RETROK_RCTRL          = 305,
+   RETROK_LCTRL          = 306,
+   RETROK_RALT           = 307,
+   RETROK_LALT           = 308,
+   RETROK_RMETA          = 309,
+   RETROK_LMETA          = 310,
+   RETROK_LSUPER         = 311,
+   RETROK_RSUPER         = 312,
+   RETROK_MODE           = 313,
+   RETROK_COMPOSE        = 314,
+
+   RETROK_HELP           = 315,
+   RETROK_PRINT          = 316,
+   RETROK_SYSREQ         = 317,
+   RETROK_BREAK          = 318,
+   RETROK_MENU           = 319,
+   RETROK_POWER          = 320,
+   RETROK_EURO           = 321,
+   RETROK_UNDO           = 322,
+   RETROK_OEM_102        = 323,
+
+   RETROK_LAST,
+
+   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
+};
+
+enum retro_mod
+{
+   RETROKMOD_NONE       = 0x0000,
+
+   RETROKMOD_SHIFT      = 0x01,
+   RETROKMOD_CTRL       = 0x02,
+   RETROKMOD_ALT        = 0x04,
+   RETROKMOD_META       = 0x08,
+
+   RETROKMOD_NUMLOCK    = 0x10,
+   RETROKMOD_CAPSLOCK   = 0x20,
+   RETROKMOD_SCROLLOCK  = 0x40,
+
+   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
+};
+
+/* If set, this call is not part of the public libretro API yet. It can
+ * change or be removed at any time. */
+#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000
+/* Environment callback to be used internally in frontend. */
+#define RETRO_ENVIRONMENT_PRIVATE 0x20000
+
+/* Environment commands. */
+#define RETRO_ENVIRONMENT_SET_ROTATION  1  /* const unsigned * --
+                                            * Sets screen rotation of graphics.
+                                            * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180,
+                                            * 270 degrees counter-clockwise respectively.
+                                            */
+#define RETRO_ENVIRONMENT_GET_OVERSCAN  2  /* bool * --
+                                            * NOTE: As of 2019 this callback is considered deprecated in favor of
+                                            * using core options to manage overscan in a more nuanced, core-specific way.
+                                            *
+                                            * Boolean value whether or not the implementation should use overscan,
+                                            * or crop away overscan.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3  /* bool * --
+                                            * Boolean value whether or not frontend supports frame duping,
+                                            * passing NULL to video frame callback.
+                                            */
+
+                                           /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
+                                            * and reserved to avoid possible ABI clash.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_MESSAGE   6  /* const struct retro_message * --
+                                            * Sets a message to be displayed in implementation-specific manner
+                                            * for a certain amount of 'frames'.
+                                            * Should not be used for trivial messages, which should simply be
+                                            * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
+                                            * fallback, stderr).
+                                            */
+#define RETRO_ENVIRONMENT_SHUTDOWN      7  /* N/A (NULL) --
+                                            * Requests the frontend to shutdown.
+                                            * Should only be used if game has a specific
+                                            * way to shutdown the game from a menu item or similar.
+                                            */
+#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8
+                                           /* const unsigned * --
+                                            * Gives a hint to the frontend how demanding this implementation
+                                            * is on a system. E.g. reporting a level of 2 means
+                                            * this implementation should run decently on all frontends
+                                            * of level 2 and up.
+                                            *
+                                            * It can be used by the frontend to potentially warn
+                                            * about too demanding implementations.
+                                            *
+                                            * The levels are "floating".
+                                            *
+                                            * This function can be called on a per-game basis,
+                                            * as certain games an implementation can play might be
+                                            * particularly demanding.
+                                            * If called, it should be called in retro_load_game().
+                                            */
+#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9
+                                           /* const char ** --
+                                            * Returns the "system" directory of the frontend.
+                                            * This directory can be used to store system specific
+                                            * content such as BIOSes, configuration data, etc.
+                                            * The returned value can be NULL.
+                                            * If so, no such directory is defined,
+                                            * and it's up to the implementation to find a suitable directory.
+                                            *
+                                            * NOTE: Some cores used this folder also for "save" data such as
+                                            * memory cards, etc, for lack of a better place to put it.
+                                            * This is now discouraged, and if possible, cores should try to
+                                            * use the new GET_SAVE_DIRECTORY.
+                                            */
+#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10
+                                           /* const enum retro_pixel_format * --
+                                            * Sets the internal pixel format used by the implementation.
+                                            * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555.
+                                            * This pixel format however, is deprecated (see enum retro_pixel_format).
+                                            * If the call returns false, the frontend does not support this pixel
+                                            * format.
+                                            *
+                                            * This function should be called inside retro_load_game() or
+                                            * retro_get_system_av_info().
+                                            */
+#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11
+                                           /* const struct retro_input_descriptor * --
+                                            * Sets an array of retro_input_descriptors.
+                                            * It is up to the frontend to present this in a usable way.
+                                            * The array is terminated by retro_input_descriptor::description
+                                            * being set to NULL.
+                                            * This function can be called at any time, but it is recommended
+                                            * to call it as early as possible.
+                                            */
+#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12
+                                           /* const struct retro_keyboard_callback * --
+                                            * Sets a callback function used to notify core about keyboard events.
+                                            */
+#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13
+                                           /* const struct retro_disk_control_callback * --
+                                            * Sets an interface which frontend can use to eject and insert
+                                            * disk images.
+                                            * This is used for games which consist of multiple images and
+                                            * must be manually swapped out by the user (e.g. PSX).
+                                            */
+#define RETRO_ENVIRONMENT_SET_HW_RENDER 14
+                                           /* struct retro_hw_render_callback * --
+                                            * Sets an interface to let a libretro core render with
+                                            * hardware acceleration.
+                                            * Should be called in retro_load_game().
+                                            * If successful, libretro cores will be able to render to a
+                                            * frontend-provided framebuffer.
+                                            * The size of this framebuffer will be at least as large as
+                                            * max_width/max_height provided in get_av_info().
+                                            * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or
+                                            * NULL to retro_video_refresh_t.
+                                            */
+#define RETRO_ENVIRONMENT_GET_VARIABLE 15
+                                           /* struct retro_variable * --
+                                            * Interface to acquire user-defined information from environment
+                                            * that cannot feasibly be supported in a multi-system way.
+                                            * 'key' should be set to a key which has already been set by
+                                            * SET_VARIABLES.
+                                            * 'data' will be set to a value or NULL.
+                                            */
+#define RETRO_ENVIRONMENT_SET_VARIABLES 16
+                                           /* const struct retro_variable * --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterward it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            *
+                                            * 'data' points to an array of retro_variable structs
+                                            * terminated by a { NULL, NULL } element.
+                                            * retro_variable::key should be namespaced to not collide
+                                            * with other implementations' keys. E.g. A core called
+                                            * 'foo' should use keys named as 'foo_option'.
+                                            * retro_variable::value should contain a human readable
+                                            * description of the key as well as a '|' delimited list
+                                            * of expected values.
+                                            *
+                                            * The number of possible options should be very limited,
+                                            * i.e. it should be feasible to cycle through options
+                                            * without a keyboard.
+                                            *
+                                            * First entry should be treated as a default.
+                                            *
+                                            * Example entry:
+                                            * { "foo_option", "Speed hack coprocessor X; false|true" }
+                                            *
+                                            * Text before first ';' is description. This ';' must be
+                                            * followed by a space, and followed by a list of possible
+                                            * values split up with '|'.
+                                            *
+                                            * Only strings are operated on. The possible values will
+                                            * generally be displayed and stored as-is by the frontend.
+                                            */
+#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17
+                                           /* bool * --
+                                            * Result is set to true if some variables are updated by
+                                            * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE.
+                                            * Variables should be queried with GET_VARIABLE.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18
+                                           /* const bool * --
+                                            * If true, the libretro implementation supports calls to
+                                            * retro_load_game() with NULL as argument.
+                                            * Used by cores which can run without particular game data.
+                                            * This should be called within retro_set_environment() only.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19
+                                           /* const char ** --
+                                            * Retrieves the absolute path from where this libretro
+                                            * implementation was loaded.
+                                            * NULL is returned if the libretro was loaded statically
+                                            * (i.e. linked statically to frontend), or if the path cannot be
+                                            * determined.
+                                            * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can
+                                            * be loaded without ugly hacks.
+                                            */
+
+                                           /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK.
+                                            * It was not used by any known core at the time,
+                                            * and was removed from the API. */
+#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
+                                           /* const struct retro_frame_time_callback * --
+                                            * Lets the core know how much time has passed since last
+                                            * invocation of retro_run().
+                                            * The frontend can tamper with the timing to fake fast-forward,
+                                            * slow-motion, frame stepping, etc.
+                                            * In this case the delta time will use the reference value
+                                            * in frame_time_callback..
+                                            */
+#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
+                                           /* const struct retro_audio_callback * --
+                                            * Sets an interface which is used to notify a libretro core about audio
+                                            * being available for writing.
+                                            * The callback can be called from any thread, so a core using this must
+                                            * have a thread safe audio implementation.
+                                            * It is intended for games where audio and video are completely
+                                            * asynchronous and audio can be generated on the fly.
+                                            * This interface is not recommended for use with emulators which have
+                                            * highly synchronous audio.
+                                            *
+                                            * The callback only notifies about writability; the libretro core still
+                                            * has to call the normal audio callbacks
+                                            * to write audio. The audio callbacks must be called from within the
+                                            * notification callback.
+                                            * The amount of audio data to write is up to the implementation.
+                                            * Generally, the audio callback will be called continously in a loop.
+                                            *
+                                            * Due to thread safety guarantees and lack of sync between audio and
+                                            * video, a frontend  can selectively disallow this interface based on
+                                            * internal configuration. A core using this interface must also
+                                            * implement the "normal" audio interface.
+                                            *
+                                            * A libretro core using SET_AUDIO_CALLBACK should also make use of
+                                            * SET_FRAME_TIME_CALLBACK.
+                                            */
+#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23
+                                           /* struct retro_rumble_interface * --
+                                            * Gets an interface which is used by a libretro core to set
+                                            * state of rumble motors in controllers.
+                                            * A strong and weak motor is supported, and they can be
+                                            * controlled indepedently.
+                                            * Should be called from either retro_init() or retro_load_game().
+                                            * Should not be called from retro_set_environment().
+                                            * Returns false if rumble functionality is unavailable.
+                                            */
+#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
+                                           /* uint64_t * --
+                                            * Gets a bitmask telling which device type are expected to be
+                                            * handled properly in a call to retro_input_state_t.
+                                            * Devices which are not handled or recognized always return
+                                            * 0 in retro_input_state_t.
+                                            * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG).
+                                            * Should only be called in retro_run().
+                                            */
+#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_sensor_interface * --
+                                            * Gets access to the sensor interface.
+                                            * The purpose of this interface is to allow
+                                            * setting state related to sensors such as polling rate,
+                                            * enabling/disable it entirely, etc.
+                                            * Reading sensor state is done via the normal
+                                            * input_state_callback API.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_camera_callback * --
+                                            * Gets an interface to a video camera driver.
+                                            * A libretro core can use this interface to get access to a
+                                            * video camera.
+                                            * New video frames are delivered in a callback in same
+                                            * thread as retro_run().
+                                            *
+                                            * GET_CAMERA_INTERFACE should be called in retro_load_game().
+                                            *
+                                            * Depending on the camera implementation used, camera frames
+                                            * will be delivered as a raw framebuffer,
+                                            * or as an OpenGL texture directly.
+                                            *
+                                            * The core has to tell the frontend here which types of
+                                            * buffers can be handled properly.
+                                            * An OpenGL texture can only be handled when using a
+                                            * libretro GL core (SET_HW_RENDER).
+                                            * It is recommended to use a libretro GL core when
+                                            * using camera interface.
+                                            *
+                                            * The camera is not started automatically. The retrieved start/stop
+                                            * functions must be used to explicitly
+                                            * start and stop the camera driver.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27
+                                           /* struct retro_log_callback * --
+                                            * Gets an interface for logging. This is useful for
+                                            * logging in a cross-platform way
+                                            * as certain platforms cannot use stderr for logging.
+                                            * It also allows the frontend to
+                                            * show logging information in a more suitable way.
+                                            * If this interface is not used, libretro cores should
+                                            * log to stderr as desired.
+                                            */
+#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28
+                                           /* struct retro_perf_callback * --
+                                            * Gets an interface for performance counters. This is useful
+                                            * for performance logging in a cross-platform way and for detecting
+                                            * architecture-specific features, such as SIMD support.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29
+                                           /* struct retro_location_callback * --
+                                            * Gets access to the location interface.
+                                            * The purpose of this interface is to be able to retrieve
+                                            * location-based information from the host device,
+                                            * such as current latitude / longitude.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 /* Old name, kept for compatibility. */
+#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30
+                                           /* const char ** --
+                                            * Returns the "core assets" directory of the frontend.
+                                            * This directory can be used to store specific assets that the
+                                            * core relies upon, such as art assets,
+                                            * input data, etc etc.
+                                            * The returned value can be NULL.
+                                            * If so, no such directory is defined,
+                                            * and it's up to the implementation to find a suitable directory.
+                                            */
+#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31
+                                           /* const char ** --
+                                            * Returns the "save" directory of the frontend, unless there is no
+                                            * save directory available. The save directory should be used to
+                                            * store SRAM, memory cards, high scores, etc, if the libretro core
+                                            * cannot use the regular memory interface (retro_get_memory_data()).
+                                            *
+                                            * If the frontend cannot designate a save directory, it will return
+                                            * NULL to indicate that the core should attempt to operate without a
+                                            * save directory set.
+                                            *
+                                            * NOTE: early libretro cores used the system directory for save
+                                            * files. Cores that need to be backwards-compatible can still check
+                                            * GET_SYSTEM_DIRECTORY.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32
+                                           /* const struct retro_system_av_info * --
+                                            * Sets a new av_info structure. This can only be called from
+                                            * within retro_run().
+                                            * This should *only* be used if the core is completely altering the
+                                            * internal resolutions, aspect ratios, timings, sampling rate, etc.
+                                            * Calling this can require a full reinitialization of video/audio
+                                            * drivers in the frontend,
+                                            *
+                                            * so it is important to call it very sparingly, and usually only with
+                                            * the users explicit consent.
+                                            * An eventual driver reinitialize will happen so that video and
+                                            * audio callbacks
+                                            * happening after this call within the same retro_run() call will
+                                            * target the newly initialized driver.
+                                            *
+                                            * This callback makes it possible to support configurable resolutions
+                                            * in games, which can be useful to
+                                            * avoid setting the "worst case" in max_width/max_height.
+                                            *
+                                            * ***HIGHLY RECOMMENDED*** Do not call this callback every time
+                                            * resolution changes in an emulator core if it's
+                                            * expected to be a temporary change, for the reasons of possible
+                                            * driver reinitialization.
+                                            * This call is not a free pass for not trying to provide
+                                            * correct values in retro_get_system_av_info(). If you need to change
+                                            * things like aspect ratio or nominal width/height,
+                                            * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant
+                                            * of SET_SYSTEM_AV_INFO.
+                                            *
+                                            * If this returns false, the frontend does not acknowledge a
+                                            * changed av_info struct.
+                                            */
+#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33
+                                           /* const struct retro_get_proc_address_interface * --
+                                            * Allows a libretro core to announce support for the
+                                            * get_proc_address() interface.
+                                            * This interface allows for a standard way to extend libretro where
+                                            * use of environment calls are too indirect,
+                                            * e.g. for cases where the frontend wants to call directly into the core.
+                                            *
+                                            * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK
+                                            * **MUST** be called from within retro_set_environment().
+                                            */
+#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34
+                                           /* const struct retro_subsystem_info * --
+                                            * This environment call introduces the concept of libretro "subsystems".
+                                            * A subsystem is a variant of a libretro core which supports
+                                            * different kinds of games.
+                                            * The purpose of this is to support e.g. emulators which might
+                                            * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo.
+                                            * It can also be used to pick among subsystems in an explicit way
+                                            * if the libretro implementation is a multi-system emulator itself.
+                                            *
+                                            * Loading a game via a subsystem is done with retro_load_game_special(),
+                                            * and this environment call allows a libretro core to expose which
+                                            * subsystems are supported for use with retro_load_game_special().
+                                            * A core passes an array of retro_game_special_info which is terminated
+                                            * with a zeroed out retro_game_special_info struct.
+                                            *
+                                            * If a core wants to use this functionality, SET_SUBSYSTEM_INFO
+                                            * **MUST** be called from within retro_set_environment().
+                                            */
+#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35
+                                           /* const struct retro_controller_info * --
+                                            * This environment call lets a libretro core tell the frontend
+                                            * which controller subclasses are recognized in calls to
+                                            * retro_set_controller_port_device().
+                                            *
+                                            * Some emulators such as Super Nintendo support multiple lightgun
+                                            * types which must be specifically selected from. It is therefore
+                                            * sometimes necessary for a frontend to be able to tell the core
+                                            * about a special kind of input device which is not specifcally
+                                            * provided by the Libretro API.
+                                            *
+                                            * In order for a frontend to understand the workings of those devices,
+                                            * they must be defined as a specialized subclass of the generic device
+                                            * types already defined in the libretro API.
+                                            *
+                                            * The core must pass an array of const struct retro_controller_info which
+                                            * is terminated with a blanked out struct. Each element of the
+                                            * retro_controller_info struct corresponds to the ascending port index
+                                            * that is passed to retro_set_controller_port_device() when that function
+                                            * is called to indicate to the core that the frontend has changed the
+                                            * active device subclass. SEE ALSO: retro_set_controller_port_device()
+                                            *
+                                            * The ascending input port indexes provided by the core in the struct
+                                            * are generally presented by frontends as ascending User # or Player #,
+                                            * such as Player 1, Player 2, Player 3, etc. Which device subclasses are
+                                            * supported can vary per input port.
+                                            *
+                                            * The first inner element of each entry in the retro_controller_info array
+                                            * is a retro_controller_description struct that specifies the names and
+                                            * codes of all device subclasses that are available for the corresponding
+                                            * User or Player, beginning with the generic Libretro device that the
+                                            * subclasses are derived from. The second inner element of each entry is the
+                                            * total number of subclasses that are listed in the retro_controller_description.
+                                            *
+                                            * NOTE: Even if special device types are set in the libretro core,
+                                            * libretro should only poll input based on the base input device types.
+                                            */
+#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const struct retro_memory_map * --
+                                            * This environment call lets a libretro core tell the frontend
+                                            * about the memory maps this core emulates.
+                                            * This can be used to implement, for example, cheats in a core-agnostic way.
+                                            *
+                                            * Should only be used by emulators; it doesn't make much sense for
+                                            * anything else.
+                                            * It is recommended to expose all relevant pointers through
+                                            * retro_get_memory_* as well.
+                                            */
+#define RETRO_ENVIRONMENT_SET_GEOMETRY 37
+                                           /* const struct retro_game_geometry * --
+                                            * This environment call is similar to SET_SYSTEM_AV_INFO for changing
+                                            * video parameters, but provides a guarantee that drivers will not be
+                                            * reinitialized.
+                                            * This can only be called from within retro_run().
+                                            *
+                                            * The purpose of this call is to allow a core to alter nominal
+                                            * width/heights as well as aspect ratios on-the-fly, which can be
+                                            * useful for some emulators to change in run-time.
+                                            *
+                                            * max_width/max_height arguments are ignored and cannot be changed
+                                            * with this call as this could potentially require a reinitialization or a
+                                            * non-constant time operation.
+                                            * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required.
+                                            *
+                                            * A frontend must guarantee that this environment call completes in
+                                            * constant time.
+                                            */
+#define RETRO_ENVIRONMENT_GET_USERNAME 38
+                                           /* const char **
+                                            * Returns the specified username of the frontend, if specified by the user.
+                                            * This username can be used as a nickname for a core that has online facilities
+                                            * or any other mode where personalization of the user is desirable.
+                                            * The returned value can be NULL.
+                                            * If this environ callback is used by a core that requires a valid username,
+                                            * a default username should be specified by the core.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LANGUAGE 39
+                                           /* unsigned * --
+                                            * Returns the specified language of the frontend, if specified by the user.
+                                            * It can be used by the core for localization purposes.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_framebuffer * --
+                                            * Returns a preallocated framebuffer which the core can use for rendering
+                                            * the frame into when not using SET_HW_RENDER.
+                                            * The framebuffer returned from this call must not be used
+                                            * after the current call to retro_run() returns.
+                                            *
+                                            * The goal of this call is to allow zero-copy behavior where a core
+                                            * can render directly into video memory, avoiding extra bandwidth cost by copying
+                                            * memory from core to video memory.
+                                            *
+                                            * If this call succeeds and the core renders into it,
+                                            * the framebuffer pointer and pitch can be passed to retro_video_refresh_t.
+                                            * If the buffer from GET_CURRENT_SOFTWARE_FRAMEBUFFER is to be used,
+                                            * the core must pass the exact
+                                            * same pointer as returned by GET_CURRENT_SOFTWARE_FRAMEBUFFER;
+                                            * i.e. passing a pointer which is offset from the
+                                            * buffer is undefined. The width, height and pitch parameters
+                                            * must also match exactly to the values obtained from GET_CURRENT_SOFTWARE_FRAMEBUFFER.
+                                            *
+                                            * It is possible for a frontend to return a different pixel format
+                                            * than the one used in SET_PIXEL_FORMAT. This can happen if the frontend
+                                            * needs to perform conversion.
+                                            *
+                                            * It is still valid for a core to render to a different buffer
+                                            * even if GET_CURRENT_SOFTWARE_FRAMEBUFFER succeeds.
+                                            *
+                                            * A frontend must make sure that the pointer obtained from this function is
+                                            * writeable (and readable).
+                                            */
+#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const struct retro_hw_render_interface ** --
+                                            * Returns an API specific rendering interface for accessing API specific data.
+                                            * Not all HW rendering APIs support or need this.
+                                            * The contents of the returned pointer is specific to the rendering API
+                                            * being used. See the various headers like libretro_vulkan.h, etc.
+                                            *
+                                            * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
+                                            * Similarly, after context_destroyed callback returns,
+                                            * the contents of the HW_RENDER_INTERFACE are invalidated.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const bool * --
+                                            * If true, the libretro implementation supports achievements
+                                            * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS
+                                            * or via retro_get_memory_data/retro_get_memory_size.
+                                            *
+                                            * This must be called before the first call to retro_run.
+                                            */
+#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const struct retro_hw_render_context_negotiation_interface * --
+                                            * Sets an interface which lets the libretro core negotiate with frontend how a context is created.
+                                            * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier.
+                                            * This interface will be used when the frontend is trying to create a HW rendering context,
+                                            * so it will be used after SET_HW_RENDER, but before the context_reset callback.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44
+                                           /* uint64_t * --
+                                            * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't
+                                            * recognize or support. Should be set in either retro_init or retro_load_game, but not both.
+                                            */
+#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* N/A (null) * --
+                                            * The frontend will try to use a 'shared' hardware context (mostly applicable
+                                            * to OpenGL) when a hardware context is being set up.
+                                            *
+                                            * Returns true if the frontend supports shared hardware contexts and false
+                                            * if the frontend does not support shared hardware contexts.
+                                            *
+                                            * This will do nothing on its own until SET_HW_RENDER env callbacks are
+                                            * being used.
+                                            */
+#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_vfs_interface_info * --
+                                            * Gets access to the VFS interface.
+                                            * VFS presence needs to be queried prior to load_game or any
+                                            * get_system/save/other_directory being called to let front end know
+                                            * core supports VFS before it starts handing out paths.
+                                            * It is recomended to do so in retro_set_environment
+                                            */
+#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_led_interface * --
+                                            * Gets an interface which is used by a libretro core to set
+                                            * state of LEDs.
+                                            */
+#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* int * --
+                                            * Tells the core if the frontend wants audio or video.
+                                            * If disabled, the frontend will discard the audio or video,
+                                            * so the core may decide to skip generating a frame or generating audio.
+                                            * This is mainly used for increasing performance.
+                                            * Bit 0 (value 1): Enable Video
+                                            * Bit 1 (value 2): Enable Audio
+                                            * Bit 2 (value 4): Use Fast Savestates.
+                                            * Bit 3 (value 8): Hard Disable Audio
+                                            * Other bits are reserved for future use and will default to zero.
+                                            * If video is disabled:
+                                            * * The frontend wants the core to not generate any video,
+                                            *   including presenting frames via hardware acceleration.
+                                            * * The frontend's video frame callback will do nothing.
+                                            * * After running the frame, the video output of the next frame should be
+                                            *   no different than if video was enabled, and saving and loading state
+                                            *   should have no issues.
+                                            * If audio is disabled:
+                                            * * The frontend wants the core to not generate any audio.
+                                            * * The frontend's audio callbacks will do nothing.
+                                            * * After running the frame, the audio output of the next frame should be
+                                            *   no different than if audio was enabled, and saving and loading state
+                                            *   should have no issues.
+                                            * Fast Savestates:
+                                            * * Guaranteed to be created by the same binary that will load them.
+                                            * * Will not be written to or read from the disk.
+                                            * * Suggest that the core assumes loading state will succeed.
+                                            * * Suggest that the core updates its memory buffers in-place if possible.
+                                            * * Suggest that the core skips clearing memory.
+                                            * * Suggest that the core skips resetting the system.
+                                            * * Suggest that the core may skip validation steps.
+                                            * Hard Disable Audio:
+                                            * * Used for a secondary core when running ahead.
+                                            * * Indicates that the frontend will never need audio from the core.
+                                            * * Suggests that the core may stop synthesizing audio, but this should not
+                                            *   compromise emulation accuracy.
+                                            * * Audio output for the next frame does not matter, and the frontend will
+                                            *   never need an accurate audio state in the future.
+                                            * * State will never be saved when using Hard Disable Audio.
+                                            */
+#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_midi_interface ** --
+                                            * Returns a MIDI interface that can be used for raw data I/O.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                            /* bool * --
+                                            * Boolean value that indicates whether or not the frontend is in
+                                            * fastforwarding mode.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                            /* float * --
+                                            * Float value that lets us know what target refresh rate
+                                            * is curently in use by the frontend.
+                                            *
+                                            * The core can use the returned value to set an ideal
+                                            * refresh rate/framerate.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                            /* bool * --
+                                            * Boolean value that indicates whether or not the frontend supports
+                                            * input bitmasks being returned by retro_input_state_t. The advantage
+                                            * of this is that retro_input_state_t has to be only called once to
+                                            * grab all button states instead of multiple times.
+                                            *
+                                            * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id'
+                                            * to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD).
+                                            * It will return a bitmask of all the digital buttons.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52
+                                           /* unsigned * --
+                                            * Unsigned value is the API version number of the core options
+                                            * interface supported by the frontend. If callback return false,
+                                            * API version is assumed to be 0.
+                                            *
+                                            * In legacy code, core options are set by passing an array of
+                                            * retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This may be still be done regardless of the core options
+                                            * interface version.
+                                            *
+                                            * If version is >= 1 however, core options may instead be set by
+                                            * passing an array of retro_core_option_definition structs to
+                                            * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
+                                            * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
+                                            * This allows the core to additionally set option sublabel information
+                                            * and/or provide localisation support.
+                                            *
+                                            * If version is >= 2, core options may instead be set by passing
+                                            * a retro_core_options_v2 struct to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
+                                            * or an array of retro_core_options_v2 structs to
+                                            * RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL. This allows the core
+                                            * to additionally set optional core option category information
+                                            * for frontends with core option category support.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53
+                                           /* const struct retro_core_option_definition ** --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
+                                            * returns an API version of >= 1.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterwards it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            *
+                                            * 'data' points to an array of retro_core_option_definition structs
+                                            * terminated by a { NULL, NULL, NULL, {{0}}, NULL } element.
+                                            * retro_core_option_definition::key should be namespaced to not collide
+                                            * with other implementations' keys. e.g. A core called
+                                            * 'foo' should use keys named as 'foo_option'.
+                                            * retro_core_option_definition::desc should contain a human readable
+                                            * description of the key.
+                                            * retro_core_option_definition::info should contain any additional human
+                                            * readable information text that a typical user may need to
+                                            * understand the functionality of the option.
+                                            * retro_core_option_definition::values is an array of retro_core_option_value
+                                            * structs terminated by a { NULL, NULL } element.
+                                            * > retro_core_option_definition::values[index].value is an expected option
+                                            *   value.
+                                            * > retro_core_option_definition::values[index].label is a human readable
+                                            *   label used when displaying the value on screen. If NULL,
+                                            *   the value itself is used.
+                                            * retro_core_option_definition::default_value is the default core option
+                                            * setting. It must match one of the expected option values in the
+                                            * retro_core_option_definition::values array. If it does not, or the
+                                            * default value is NULL, the first entry in the
+                                            * retro_core_option_definition::values array is treated as the default.
+                                            *
+                                            * The number of possible option values should be very limited,
+                                            * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX.
+                                            * i.e. it should be feasible to cycle through options
+                                            * without a keyboard.
+                                            *
+                                            * Example entry:
+                                            * {
+                                            *     "foo_option",
+                                            *     "Speed hack coprocessor X",
+                                            *     "Provides increased performance at the expense of reduced accuracy",
+                                            *    {
+                                            *         { "false",    NULL },
+                                            *         { "true",     NULL },
+                                            *         { "unstable", "Turbo (Unstable)" },
+                                            *         { NULL, NULL },
+                                            *     },
+                                            *     "false"
+                                            * }
+                                            *
+                                            * Only strings are operated on. The possible values will
+                                            * generally be displayed and stored as-is by the frontend.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54
+                                           /* const struct retro_core_options_intl * --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
+                                            * returns an API version of >= 1.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterwards it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            *
+                                            * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
+                                            * with the addition of localisation support. The description of the
+                                            * RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted
+                                            * for further details.
+                                            *
+                                            * 'data' points to a retro_core_options_intl struct.
+                                            *
+                                            * retro_core_options_intl::us is a pointer to an array of
+                                            * retro_core_option_definition structs defining the US English
+                                            * core options implementation. It must point to a valid array.
+                                            *
+                                            * retro_core_options_intl::local is a pointer to an array of
+                                            * retro_core_option_definition structs defining core options for
+                                            * the current frontend language. It may be NULL (in which case
+                                            * retro_core_options_intl::us is used by the frontend). Any items
+                                            * missing from this array will be read from retro_core_options_intl::us
+                                            * instead.
+                                            *
+                                            * NOTE: Default core option values are always taken from the
+                                            * retro_core_options_intl::us array. Any default values in
+                                            * retro_core_options_intl::local array will be ignored.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55
+                                           /* struct retro_core_option_display * --
+                                            *
+                                            * Allows an implementation to signal the environment to show
+                                            * or hide a variable when displaying core options. This is
+                                            * considered a *suggestion*. The frontend is free to ignore
+                                            * this callback, and its implementation not considered mandatory.
+                                            *
+                                            * 'data' points to a retro_core_option_display struct
+                                            *
+                                            * retro_core_option_display::key is a variable identifier
+                                            * which has already been set by SET_VARIABLES/SET_CORE_OPTIONS.
+                                            *
+                                            * retro_core_option_display::visible is a boolean, specifying
+                                            * whether variable should be displayed
+                                            *
+                                            * Note that all core option variables will be set visible by
+                                            * default when calling SET_VARIABLES/SET_CORE_OPTIONS.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56
+                                           /* unsigned * --
+                                            *
+                                            * Allows an implementation to ask frontend preferred hardware
+                                            * context to use. Core should use this information to deal
+                                            * with what specific context to request with SET_HW_RENDER.
+                                            *
+                                            * 'data' points to an unsigned variable
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57
+                                           /* unsigned * --
+                                            * Unsigned value is the API version number of the disk control
+                                            * interface supported by the frontend. If callback return false,
+                                            * API version is assumed to be 0.
+                                            *
+                                            * In legacy code, the disk control interface is defined by passing
+                                            * a struct of type retro_disk_control_callback to
+                                            * RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
+                                            * This may be still be done regardless of the disk control
+                                            * interface version.
+                                            *
+                                            * If version is >= 1 however, the disk control interface may
+                                            * instead be defined by passing a struct of type
+                                            * retro_disk_control_ext_callback to
+                                            * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
+                                            * This allows the core to provide additional information about
+                                            * disk images to the frontend and/or enables extra
+                                            * disk control functionality by the frontend.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58
+                                           /* const struct retro_disk_control_ext_callback * --
+                                            * Sets an interface which frontend can use to eject and insert
+                                            * disk images, and also obtain information about individual
+                                            * disk image files registered by the core.
+                                            * This is used for games which consist of multiple images and
+                                            * must be manually swapped out by the user (e.g. PSX, floppy disk
+                                            * based systems).
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59
+                                           /* unsigned * --
+                                            * Unsigned value is the API version number of the message
+                                            * interface supported by the frontend. If callback returns
+                                            * false, API version is assumed to be 0.
+                                            *
+                                            * In legacy code, messages may be displayed in an
+                                            * implementation-specific manner by passing a struct
+                                            * of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE.
+                                            * This may be still be done regardless of the message
+                                            * interface version.
+                                            *
+                                            * If version is >= 1 however, messages may instead be
+                                            * displayed by passing a struct of type retro_message_ext
+                                            * to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the
+                                            * core to specify message logging level, priority and
+                                            * destination (OSD, logging interface or both).
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60
+                                           /* const struct retro_message_ext * --
+                                            * Sets a message to be displayed in an implementation-specific
+                                            * manner for a certain amount of 'frames'. Additionally allows
+                                            * the core to specify message logging level, priority and
+                                            * destination (OSD, logging interface or both).
+                                            * Should not be used for trivial messages, which should simply be
+                                            * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
+                                            * fallback, stderr).
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61
+                                           /* unsigned * --
+                                            * Unsigned value is the number of active input devices
+                                            * provided by the frontend. This may change between
+                                            * frames, but will remain constant for the duration
+                                            * of each frame.
+                                            * If callback returns true, a core need not poll any
+                                            * input device with an index greater than or equal to
+                                            * the number of active devices.
+                                            * If callback returns false, the number of active input
+                                            * devices is unknown. In this case, all input devices
+                                            * should be considered active.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62
+                                           /* const struct retro_audio_buffer_status_callback * --
+                                            * Lets the core know the occupancy level of the frontend
+                                            * audio buffer. Can be used by a core to attempt frame
+                                            * skipping in order to avoid buffer under-runs.
+                                            * A core may pass NULL to disable buffer status reporting
+                                            * in the frontend.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63
+                                           /* const unsigned * --
+                                            * Sets minimum frontend audio latency in milliseconds.
+                                            * Resultant audio latency may be larger than set value,
+                                            * or smaller if a hardware limit is encountered. A frontend
+                                            * is expected to honour requests up to 512 ms.
+                                            *
+                                            * - If value is less than current frontend
+                                            *   audio latency, callback has no effect
+                                            * - If value is zero, default frontend audio
+                                            *   latency is set
+                                            *
+                                            * May be used by a core to increase audio latency and
+                                            * therefore decrease the probability of buffer under-runs
+                                            * (crackling) when performing 'intensive' operations.
+                                            * A core utilising RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
+                                            * to implement audio-buffer-based frame skipping may achieve
+                                            * optimal results by setting the audio latency to a 'high'
+                                            * (typically 6x or 8x) integer multiple of the expected
+                                            * frame time.
+                                            *
+                                            * WARNING: This can only be called from within retro_run().
+                                            * Calling this can require a full reinitialization of audio
+                                            * drivers in the frontend, so it is important to call it very
+                                            * sparingly, and usually only with the users explicit consent.
+                                            * An eventual driver reinitialize will happen so that audio
+                                            * callbacks happening after this call within the same retro_run()
+                                            * call will target the newly initialized driver.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64
+                                           /* const struct retro_fastforwarding_override * --
+                                            * Used by a libretro core to override the current
+                                            * fastforwarding mode of the frontend.
+                                            * If NULL is passed to this function, the frontend
+                                            * will return true if fastforwarding override
+                                            * functionality is supported (no change in
+                                            * fastforwarding state will occur in this case).
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65
+                                           /* const struct retro_system_content_info_override * --
+                                            * Allows an implementation to override 'global' content
+                                            * info parameters reported by retro_get_system_info().
+                                            * Overrides also affect subsystem content info parameters
+                                            * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.
+                                            * This function must be called inside retro_set_environment().
+                                            * If callback returns false, content info overrides
+                                            * are unsupported by the frontend, and will be ignored.
+                                            * If callback returns true, extended game info may be
+                                            * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
+                                            * in retro_load_game() or retro_load_game_special().
+                                            *
+                                            * 'data' points to an array of retro_system_content_info_override
+                                            * structs terminated by a { NULL, false, false } element.
+                                            * If 'data' is NULL, no changes will be made to the frontend;
+                                            * a core may therefore pass NULL in order to test whether
+                                            * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and
+                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported
+                                            * by the frontend.
+                                            *
+                                            * For struct member descriptions, see the definition of
+                                            * struct retro_system_content_info_override.
+                                            *
+                                            * Example:
+                                            *
+                                            * - struct retro_system_info:
+                                            * {
+                                            *    "My Core",                      // library_name
+                                            *    "v1.0",                         // library_version
+                                            *    "m3u|md|cue|iso|chd|sms|gg|sg", // valid_extensions
+                                            *    true,                           // need_fullpath
+                                            *    false                           // block_extract
+                                            * }
+                                            *
+                                            * - Array of struct retro_system_content_info_override:
+                                            * {
+                                            *    {
+                                            *       "md|sms|gg", // extensions
+                                            *       false,       // need_fullpath
+                                            *       true         // persistent_data
+                                            *    },
+                                            *    {
+                                            *       "sg",        // extensions
+                                            *       false,       // need_fullpath
+                                            *       false        // persistent_data
+                                            *    },
+                                            *    { NULL, false, false }
+                                            * }
+                                            *
+                                            * Result:
+                                            * - Files of type m3u, cue, iso, chd will not be
+                                            *   loaded by the frontend. Frontend will pass a
+                                            *   valid path to the core, and core will handle
+                                            *   loading internally
+                                            * - Files of type md, sms, gg will be loaded by
+                                            *   the frontend. A valid memory buffer will be
+                                            *   passed to the core. This memory buffer will
+                                            *   remain valid until retro_deinit() returns
+                                            * - Files of type sg will be loaded by the frontend.
+                                            *   A valid memory buffer will be passed to the core.
+                                            *   This memory buffer will remain valid until
+                                            *   retro_load_game() (or retro_load_game_special())
+                                            *   returns
+                                            *
+                                            * NOTE: If an extension is listed multiple times in
+                                            * an array of retro_system_content_info_override
+                                            * structs, only the first instance will be registered
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66
+                                           /* const struct retro_game_info_ext ** --
+                                            * Allows an implementation to fetch extended game
+                                            * information, providing additional content path
+                                            * and memory buffer status details.
+                                            * This function may only be called inside
+                                            * retro_load_game() or retro_load_game_special().
+                                            * If callback returns false, extended game information
+                                            * is unsupported by the frontend. In this case, only
+                                            * regular retro_game_info will be available.
+                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed
+                                            * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
+                                            * returns true.
+                                            *
+                                            * 'data' points to an array of retro_game_info_ext structs.
+                                            *
+                                            * For struct member descriptions, see the definition of
+                                            * struct retro_game_info_ext.
+                                            *
+                                            * - If function is called inside retro_load_game(),
+                                            *   the retro_game_info_ext array is guaranteed to
+                                            *   have a size of 1 - i.e. the returned pointer may
+                                            *   be used to access directly the members of the
+                                            *   first retro_game_info_ext struct, for example:
+                                            *
+                                            *      struct retro_game_info_ext *game_info_ext;
+                                            *      if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext))
+                                            *         printf("Content Directory: %s\n", game_info_ext->dir);
+                                            *
+                                            * - If the function is called inside retro_load_game_special(),
+                                            *   the retro_game_info_ext array is guaranteed to have a
+                                            *   size equal to the num_info argument passed to
+                                            *   retro_load_game_special()
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 67
+                                           /* const struct retro_core_options_v2 * --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
+                                            * returns an API version of >= 2.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterwards it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            * If RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION returns an API
+                                            * version of >= 2, this callback is guaranteed to succeed
+                                            * (i.e. callback return value does not indicate success)
+                                            * If callback returns true, frontend has core option category
+                                            * support.
+                                            * If callback returns false, frontend does not have core option
+                                            * category support.
+                                            *
+                                            * 'data' points to a retro_core_options_v2 struct, containing
+                                            * of two pointers:
+                                            * - retro_core_options_v2::categories is an array of
+                                            *   retro_core_option_v2_category structs terminated by a
+                                            *   { NULL, NULL, NULL } element. If retro_core_options_v2::categories
+                                            *   is NULL, all core options will have no category and will be shown
+                                            *   at the top level of the frontend core option interface. If frontend
+                                            *   does not have core option category support, categories array will
+                                            *   be ignored.
+                                            * - retro_core_options_v2::definitions is an array of
+                                            *   retro_core_option_v2_definition structs terminated by a
+                                            *   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }
+                                            *   element.
+                                            *
+                                            * >> retro_core_option_v2_category notes:
+                                            *
+                                            * - retro_core_option_v2_category::key should contain string
+                                            *   that uniquely identifies the core option category. Valid
+                                            *   key characters are [a-z, A-Z, 0-9, _, -]
+                                            *   Namespace collisions with other implementations' category
+                                            *   keys are permitted.
+                                            * - retro_core_option_v2_category::desc should contain a human
+                                            *   readable description of the category key.
+                                            * - retro_core_option_v2_category::info should contain any
+                                            *   additional human readable information text that a typical
+                                            *   user may need to understand the nature of the core option
+                                            *   category.
+                                            *
+                                            * Example entry:
+                                            * {
+                                            *     "advanced_settings",
+                                            *     "Advanced",
+                                            *     "Options affecting low-level emulation performance and accuracy."
+                                            * }
+                                            *
+                                            * >> retro_core_option_v2_definition notes:
+                                            *
+                                            * - retro_core_option_v2_definition::key should be namespaced to not
+                                            *   collide with other implementations' keys. e.g. A core called
+                                            *   'foo' should use keys named as 'foo_option'. Valid key characters
+                                            *   are [a-z, A-Z, 0-9, _, -].
+                                            * - retro_core_option_v2_definition::desc should contain a human readable
+                                            *   description of the key. Will be used when the frontend does not
+                                            *   have core option category support. Examples: "Aspect Ratio" or
+                                            *   "Video > Aspect Ratio".
+                                            * - retro_core_option_v2_definition::desc_categorized should contain a
+                                            *   human readable description of the key, which will be used when
+                                            *   frontend has core option category support. Example: "Aspect Ratio",
+                                            *   where associated retro_core_option_v2_category::desc is "Video".
+                                            *   If empty or NULL, the string specified by
+                                            *   retro_core_option_v2_definition::desc will be used instead.
+                                            *   retro_core_option_v2_definition::desc_categorized will be ignored
+                                            *   if retro_core_option_v2_definition::category_key is empty or NULL.
+                                            * - retro_core_option_v2_definition::info should contain any additional
+                                            *   human readable information text that a typical user may need to
+                                            *   understand the functionality of the option.
+                                            * - retro_core_option_v2_definition::info_categorized should contain
+                                            *   any additional human readable information text that a typical user
+                                            *   may need to understand the functionality of the option, and will be
+                                            *   used when frontend has core option category support. This is provided
+                                            *   to accommodate the case where info text references an option by
+                                            *   name/desc, and the desc/desc_categorized text for that option differ.
+                                            *   If empty or NULL, the string specified by
+                                            *   retro_core_option_v2_definition::info will be used instead.
+                                            *   retro_core_option_v2_definition::info_categorized will be ignored
+                                            *   if retro_core_option_v2_definition::category_key is empty or NULL.
+                                            * - retro_core_option_v2_definition::category_key should contain a
+                                            *   category identifier (e.g. "video" or "audio") that will be
+                                            *   assigned to the core option if frontend has core option category
+                                            *   support. A categorized option will be shown in a subsection/
+                                            *   submenu of the frontend core option interface. If key is empty
+                                            *   or NULL, or if key does not match one of the
+                                            *   retro_core_option_v2_category::key values in the associated
+                                            *   retro_core_option_v2_category array, option will have no category
+                                            *   and will be shown at the top level of the frontend core option
+                                            *   interface.
+                                            * - retro_core_option_v2_definition::values is an array of
+                                            *   retro_core_option_value structs terminated by a { NULL, NULL }
+                                            *   element.
+                                            * --> retro_core_option_v2_definition::values[index].value is an
+                                            *     expected option value.
+                                            * --> retro_core_option_v2_definition::values[index].label is a
+                                            *     human readable label used when displaying the value on screen.
+                                            *     If NULL, the value itself is used.
+                                            * - retro_core_option_v2_definition::default_value is the default
+                                            *   core option setting. It must match one of the expected option
+                                            *   values in the retro_core_option_v2_definition::values array. If
+                                            *   it does not, or the default value is NULL, the first entry in the
+                                            *   retro_core_option_v2_definition::values array is treated as the
+                                            *   default.
+                                            *
+                                            * The number of possible option values should be very limited,
+                                            * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX.
+                                            * i.e. it should be feasible to cycle through options
+                                            * without a keyboard.
+                                            *
+                                            * Example entries:
+                                            *
+                                            * - Uncategorized:
+                                            *
+                                            * {
+                                            *     "foo_option",
+                                            *     "Speed hack coprocessor X",
+                                            *     NULL,
+                                            *     "Provides increased performance at the expense of reduced accuracy.",
+                                            *     NULL,
+                                            *     NULL,
+                                            *    {
+                                            *         { "false",    NULL },
+                                            *         { "true",     NULL },
+                                            *         { "unstable", "Turbo (Unstable)" },
+                                            *         { NULL, NULL },
+                                            *     },
+                                            *     "false"
+                                            * }
+                                            *
+                                            * - Categorized:
+                                            *
+                                            * {
+                                            *     "foo_option",
+                                            *     "Advanced > Speed hack coprocessor X",
+                                            *     "Speed hack coprocessor X",
+                                            *     "Setting 'Advanced > Speed hack coprocessor X' to 'true' or 'Turbo' provides increased performance at the expense of reduced accuracy",
+                                            *     "Setting 'Speed hack coprocessor X' to 'true' or 'Turbo' provides increased performance at the expense of reduced accuracy",
+                                            *     "advanced_settings",
+                                            *    {
+                                            *         { "false",    NULL },
+                                            *         { "true",     NULL },
+                                            *         { "unstable", "Turbo (Unstable)" },
+                                            *         { NULL, NULL },
+                                            *     },
+                                            *     "false"
+                                            * }
+                                            *
+                                            * Only strings are operated on. The possible values will
+                                            * generally be displayed and stored as-is by the frontend.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL 68
+                                           /* const struct retro_core_options_v2_intl * --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
+                                            * returns an API version of >= 2.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterwards it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            * If RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION returns an API
+                                            * version of >= 2, this callback is guaranteed to succeed
+                                            * (i.e. callback return value does not indicate success)
+                                            * If callback returns true, frontend has core option category
+                                            * support.
+                                            * If callback returns false, frontend does not have core option
+                                            * category support.
+                                            *
+                                            * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
+                                            * with the addition of localisation support. The description of the
+                                            * RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 callback should be consulted
+                                            * for further details.
+                                            *
+                                            * 'data' points to a retro_core_options_v2_intl struct.
+                                            *
+                                            * - retro_core_options_v2_intl::us is a pointer to a
+                                            *   retro_core_options_v2 struct defining the US English
+                                            *   core options implementation. It must point to a valid struct.
+                                            *
+                                            * - retro_core_options_v2_intl::local is a pointer to a
+                                            *   retro_core_options_v2 struct defining core options for
+                                            *   the current frontend language. It may be NULL (in which case
+                                            *   retro_core_options_v2_intl::us is used by the frontend). Any items
+                                            *   missing from this struct will be read from
+                                            *   retro_core_options_v2_intl::us instead.
+                                            *
+                                            * NOTE: Default core option values are always taken from the
+                                            * retro_core_options_v2_intl::us struct. Any default values in
+                                            * the retro_core_options_v2_intl::local struct will be ignored.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69
+                                           /* const struct retro_core_options_update_display_callback * --
+                                            * Allows a frontend to signal that a core must update
+                                            * the visibility of any dynamically hidden core options,
+                                            * and enables the frontend to detect visibility changes.
+                                            * Used by the frontend to update the menu display status
+                                            * of core options without requiring a call of retro_run().
+                                            * Must be called in retro_set_environment().
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_VARIABLE 70
+                                           /* const struct retro_variable * --
+                                            * Allows an implementation to notify the frontend
+                                            * that a core option value has changed.
+                                            *
+                                            * retro_variable::key and retro_variable::value
+                                            * must match strings that have been set previously
+                                            * via one of the following:
+                                            *
+                                            * - RETRO_ENVIRONMENT_SET_VARIABLES
+                                            * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS
+                                            * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL
+                                            * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2
+                                            * - RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL
+                                            *
+                                            * After changing a core option value via this
+                                            * callback, RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE
+                                            * will return true.
+                                            *
+                                            * If data is NULL, no changes will be registered
+                                            * and the callback will return true; an
+                                            * implementation may therefore pass NULL in order
+                                            * to test whether the callback is supported.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_throttle_state * --
+                                            * Allows an implementation to get details on the actual rate
+                                            * the frontend is attempting to call retro_run().
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* int * --
+                                            * Tells the core about the context the frontend is asking for savestate.
+                                            * (see enum retro_savestate_context)
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                            /* struct retro_hw_render_context_negotiation_interface * --
+                                             * Before calling SET_HW_RNEDER_CONTEXT_NEGOTIATION_INTERFACE, a core can query
+                                             * which version of the interface is supported.
+                                             *
+                                             * Frontend looks at interface_type and returns the maximum supported
+                                             * context negotiation interface version.
+                                             * If the interface_type is not supported or recognized by the frontend, a version of 0
+                                             * must be returned in interface_version and true is returned by frontend.
+                                             *
+                                             * If this environment call returns true with interface_version greater than 0,
+                                             * a core can always use a negotiation interface version larger than what the frontend returns, but only
+                                             * earlier versions of the interface will be used by the frontend.
+                                             * A frontend must not reject a negotiation interface version that is larger than
+                                             * what the frontend supports. Instead, the frontend will use the older entry points that it recognizes.
+                                             * If this is incompatible with a particular core's requirements, it can error out early.
+                                             *
+                                             * Backwards compatibility note:
+                                             * This environment call was introduced after Vulkan v1 context negotiation.
+                                             * If this environment call is not supported by frontend - i.e. the environment call returns false -
+                                             * only Vulkan v1 context negotiation is supported (if Vulkan HW rendering is supported at all).
+                                             * If a core uses Vulkan negotiation interface with version > 1, negotiation may fail unexpectedly.
+                                             * All future updates to the context negotiation interface implies that frontend must support
+                                             * this environment call to query support.
+                                             */
+
+#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74
+                                           /* bool * --
+                                            * Result is set to true if the frontend has already verified JIT can be
+                                            * used, mainly for use iOS/tvOS. On other platforms the result is true.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_microphone_interface * --
+                                            * Returns an interface that can be used to receive input from the microphone driver.
+                                            *
+                                            * Returns true if microphone support is available,
+                                            * even if no microphones are plugged in.
+                                            * Returns false if mic support is disabled or unavailable.
+                                            *
+                                            * This callback can be invoked at any time,
+                                            * even before the microphone driver is ready.
+                                            */
+
+/* VFS functionality */
+
+/* File paths:
+ * File paths passed as parameters when using this API shall be well formed UNIX-style,
+ * using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator.
+ * Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead).
+ * Other than the directory separator, cores shall not make assumptions about path format:
+ * "C:/path/game.bin", "http://example.com/game.bin", "#game/game.bin", "./game.bin" (without quotes) are all valid paths.
+ * Cores may replace the basename or remove path components from the end, and/or add new components;
+ * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request to front end.
+ * The frontend is encouraged to make such paths work as well as it can, but is allowed to give up if the core alters paths too much.
+ * Frontends are encouraged, but not required, to support native file system paths (modulo replacing the directory separator, if applicable).
+ * Cores are allowed to try using them, but must remain functional if the front rejects such requests.
+ * Cores are encouraged to use the libretro-common filestream functions for file I/O,
+ * as they seamlessly integrate with VFS, deal with directory separator replacement as appropriate
+ * and provide platform-specific fallbacks in cases where front ends do not support VFS. */
+
+/* Opaque file handle
+ * Introduced in VFS API v1 */
+struct retro_vfs_file_handle;
+
+/* Opaque directory handle
+ * Introduced in VFS API v3 */
+struct retro_vfs_dir_handle;
+
+/* File open flags
+ * Introduced in VFS API v1 */
+#define RETRO_VFS_FILE_ACCESS_READ            (1 << 0) /* Read only mode */
+#define RETRO_VFS_FILE_ACCESS_WRITE           (1 << 1) /* Write only mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified */
+#define RETRO_VFS_FILE_ACCESS_READ_WRITE      (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE) /* Read-write mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified*/
+#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */
+
+/* These are only hints. The frontend may choose to ignore them. Other than RAM/CPU/etc use,
+   and how they react to unlikely external interference (for example someone else writing to that file,
+   or the file's server going down), behavior will not change. */
+#define RETRO_VFS_FILE_ACCESS_HINT_NONE              (0)
+/* Indicate that the file will be accessed many times. The frontend should aggressively cache everything. */
+#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS   (1 << 0)
+
+/* Seek positions */
+#define RETRO_VFS_SEEK_POSITION_START    0
+#define RETRO_VFS_SEEK_POSITION_CURRENT  1
+#define RETRO_VFS_SEEK_POSITION_END      2
+
+/* stat() result flags
+ * Introduced in VFS API v3 */
+#define RETRO_VFS_STAT_IS_VALID               (1 << 0)
+#define RETRO_VFS_STAT_IS_DIRECTORY           (1 << 1)
+#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL   (1 << 2)
+
+/* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle
+ * Introduced in VFS API v1 */
+typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);
+
+/* Open a file for reading or writing. If path points to a directory, this will
+ * fail. Returns the opaque file handle, or NULL for error.
+ * Introduced in VFS API v1 */
+typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);
+
+/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure.
+ * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);
+
+/* Return the size of the file in bytes, or -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);
+
+/* Truncate file to specified size. Returns 0 on success or -1 on error
+ * Introduced in VFS API v2 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);
+
+/* Get the current read / write position for the file. Returns -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);
+
+/* Set the current read/write position for the file. Returns the new position, -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);
+
+/* Read data from a file. Returns the number of bytes read, or -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);
+
+/* Write data to a file. Returns the number of bytes written, or -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);
+
+/* Flush pending writes to file, if using buffered IO. Returns 0 on sucess, or -1 on failure.
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);
+
+/* Delete the specified file. Returns 0 on success, -1 on failure
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);
+
+/* Rename the specified file. Returns 0 on success, -1 on failure
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);
+
+/* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid.
+ * Additionally stores file size in given variable, unless NULL is given.
+ * Introduced in VFS API v3 */
+typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);
+
+/* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists.
+ * Introduced in VFS API v3 */
+typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);
+
+/* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error.
+ * Support for the include_hidden argument may vary depending on the platform.
+ * Introduced in VFS API v3 */
+typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);
+
+/* Read the directory entry at the current position, and move the read pointer to the next position.
+ * Returns true on success, false if already on the last entry.
+ * Introduced in VFS API v3 */
+typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);
+
+/* Get the name of the last entry read. Returns a string on success, or NULL for error.
+ * The returned string pointer is valid until the next call to readdir or closedir.
+ * Introduced in VFS API v3 */
+typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);
+
+/* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error).
+ * Introduced in VFS API v3 */
+typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);
+
+/* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure.
+ * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
+ * Introduced in VFS API v3 */
+typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);
+
+struct retro_vfs_interface
+{
+   /* VFS API v1 */
+       retro_vfs_get_path_t get_path;
+       retro_vfs_open_t open;
+       retro_vfs_close_t close;
+       retro_vfs_size_t size;
+       retro_vfs_tell_t tell;
+       retro_vfs_seek_t seek;
+       retro_vfs_read_t read;
+       retro_vfs_write_t write;
+       retro_vfs_flush_t flush;
+       retro_vfs_remove_t remove;
+       retro_vfs_rename_t rename;
+   /* VFS API v2 */
+   retro_vfs_truncate_t truncate;
+   /* VFS API v3 */
+   retro_vfs_stat_t stat;
+   retro_vfs_mkdir_t mkdir;
+   retro_vfs_opendir_t opendir;
+   retro_vfs_readdir_t readdir;
+   retro_vfs_dirent_get_name_t dirent_get_name;
+   retro_vfs_dirent_is_dir_t dirent_is_dir;
+   retro_vfs_closedir_t closedir;
+};
+
+struct retro_vfs_interface_info
+{
+   /* Set by core: should this be higher than the version the front end supports,
+    * front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call
+    * Introduced in VFS API v1 */
+   uint32_t required_interface_version;
+
+   /* Frontend writes interface pointer here. The frontend also sets the actual
+    * version, must be at least required_interface_version.
+    * Introduced in VFS API v1 */
+   struct retro_vfs_interface *iface;
+};
+
+enum retro_hw_render_interface_type
+{
+   RETRO_HW_RENDER_INTERFACE_VULKAN     = 0,
+   RETRO_HW_RENDER_INTERFACE_D3D9       = 1,
+   RETRO_HW_RENDER_INTERFACE_D3D10      = 2,
+   RETRO_HW_RENDER_INTERFACE_D3D11      = 3,
+   RETRO_HW_RENDER_INTERFACE_D3D12      = 4,
+   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2  = 5,
+   RETRO_HW_RENDER_INTERFACE_DUMMY      = INT_MAX
+};
+
+/* Base struct. All retro_hw_render_interface_* types
+ * contain at least these fields. */
+struct retro_hw_render_interface
+{
+   enum retro_hw_render_interface_type interface_type;
+   unsigned interface_version;
+};
+
+typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);
+struct retro_led_interface
+{
+    retro_set_led_state_t set_led_state;
+};
+
+/* Retrieves the current state of the MIDI input.
+ * Returns true if it's enabled, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);
+
+/* Retrieves the current state of the MIDI output.
+ * Returns true if it's enabled, false otherwise */
+typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);
+
+/* Reads next byte from the input stream.
+ * Returns true if byte is read, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);
+
+/* Writes byte to the output stream.
+ * 'delta_time' is in microseconds and represent time elapsed since previous write.
+ * Returns true if byte is written, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);
+
+/* Flushes previously written data.
+ * Returns true if successful, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);
+
+struct retro_midi_interface
+{
+   retro_midi_input_enabled_t input_enabled;
+   retro_midi_output_enabled_t output_enabled;
+   retro_midi_read_t read;
+   retro_midi_write_t write;
+   retro_midi_flush_t flush;
+};
+
+enum retro_hw_render_context_negotiation_interface_type
+{
+   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,
+   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX
+};
+
+/* Base struct. All retro_hw_render_context_negotiation_interface_* types
+ * contain at least these fields. */
+struct retro_hw_render_context_negotiation_interface
+{
+   enum retro_hw_render_context_negotiation_interface_type interface_type;
+   unsigned interface_version;
+};
+
+/* Serialized state is incomplete in some way. Set if serialization is
+ * usable in typical end-user cases but should not be relied upon to
+ * implement frame-sensitive frontend features such as netplay or
+ * rerecording. */
+#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0)
+/* The core must spend some time initializing before serialization is
+ * supported. retro_serialize() will initially fail; retro_unserialize()
+ * and retro_serialize_size() may or may not work correctly either. */
+#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1)
+/* Serialization size may change within a session. */
+#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2)
+/* Set by the frontend to acknowledge that it supports variable-sized
+ * states. */
+#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3)
+/* Serialized state can only be loaded during the same session. */
+#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4)
+/* Serialized state cannot be loaded on an architecture with a different
+ * endianness from the one it was saved on. */
+#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5)
+/* Serialized state cannot be loaded on a different platform from the one it
+ * was saved on for reasons other than endianness, such as word size
+ * dependence */
+#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)
+
+#define RETRO_MEMDESC_CONST      (1 << 0)   /* The frontend will never change this memory area once retro_load_game has returned. */
+#define RETRO_MEMDESC_BIGENDIAN  (1 << 1)   /* The memory area contains big endian data. Default is little endian. */
+#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2)   /* The memory area is system RAM.  This is main RAM of the gaming system. */
+#define RETRO_MEMDESC_SAVE_RAM   (1 << 3)   /* The memory area is save RAM. This RAM is usually found on a game cartridge, backed up by a battery. */
+#define RETRO_MEMDESC_VIDEO_RAM  (1 << 4)   /* The memory area is video RAM (VRAM) */
+#define RETRO_MEMDESC_ALIGN_2    (1 << 16)  /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
+#define RETRO_MEMDESC_ALIGN_4    (2 << 16)
+#define RETRO_MEMDESC_ALIGN_8    (3 << 16)
+#define RETRO_MEMDESC_MINSIZE_2  (1 << 24)  /* All memory in this region is accessed at least 2 bytes at the time. */
+#define RETRO_MEMDESC_MINSIZE_4  (2 << 24)
+#define RETRO_MEMDESC_MINSIZE_8  (3 << 24)
+struct retro_memory_descriptor
+{
+   uint64_t flags;
+
+   /* Pointer to the start of the relevant ROM or RAM chip.
+    * It's strongly recommended to use 'offset' if possible, rather than
+    * doing math on the pointer.
+    *
+    * If the same byte is mapped my multiple descriptors, their descriptors
+    * must have the same pointer.
+    * If 'start' does not point to the first byte in the pointer, put the
+    * difference in 'offset' instead.
+    *
+    * May be NULL if there's nothing usable here (e.g. hardware registers and
+    * open bus). No flags should be set if the pointer is NULL.
+    * It's recommended to minimize the number of descriptors if possible,
+    * but not mandatory. */
+   void *ptr;
+   size_t offset;
+
+   /* This is the location in the emulated address space
+    * where the mapping starts. */
+   size_t start;
+
+   /* Which bits must be same as in 'start' for this mapping to apply.
+    * The first memory descriptor to claim a certain byte is the one
+    * that applies.
+    * A bit which is set in 'start' must also be set in this.
+    * Can be zero, in which case each byte is assumed mapped exactly once.
+    * In this case, 'len' must be a power of two. */
+   size_t select;
+
+   /* If this is nonzero, the set bits are assumed not connected to the
+    * memory chip's address pins. */
+   size_t disconnect;
+
+   /* This one tells the size of the current memory area.
+    * If, after start+disconnect are applied, the address is higher than
+    * this, the highest bit of the address is cleared.
+    *
+    * If the address is still too high, the next highest bit is cleared.
+    * Can be zero, in which case it's assumed to be infinite (as limited
+    * by 'select' and 'disconnect'). */
+   size_t len;
+
+   /* To go from emulated address to physical address, the following
+    * order applies:
+    * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. */
+
+   /* The address space name must consist of only a-zA-Z0-9_-,
+    * should be as short as feasible (maximum length is 8 plus the NUL),
+    * and may not be any other address space plus one or more 0-9A-F
+    * at the end.
+    * However, multiple memory descriptors for the same address space is
+    * allowed, and the address space name can be empty. NULL is treated
+    * as empty.
+    *
+    * Address space names are case sensitive, but avoid lowercase if possible.
+    * The same pointer may exist in multiple address spaces.
+    *
+    * Examples:
+    * blank+blank - valid (multiple things may be mapped in the same namespace)
+    * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace)
+    * 'A'+'B' - valid (neither is a prefix of each other)
+    * 'S'+blank - valid ('S' is not in 0-9A-F)
+    * 'a'+blank - valid ('a' is not in 0-9A-F)
+    * 'a'+'A' - valid (neither is a prefix of each other)
+    * 'AR'+blank - valid ('R' is not in 0-9A-F)
+    * 'ARB'+blank - valid (the B can't be part of the address either, because
+    *                      there is no namespace 'AR')
+    * blank+'B' - not valid, because it's ambigous which address space B1234
+    *             would refer to.
+    * The length can't be used for that purpose; the frontend may want
+    * to append arbitrary data to an address, without a separator. */
+   const char *addrspace;
+
+   /* TODO: When finalizing this one, add a description field, which should be
+    * "WRAM" or something roughly equally long. */
+
+   /* TODO: When finalizing this one, replace 'select' with 'limit', which tells
+    * which bits can vary and still refer to the same address (limit = ~select).
+    * TODO: limit? range? vary? something else? */
+
+   /* TODO: When finalizing this one, if 'len' is above what 'select' (or
+    * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'
+    * and 'select' != 0, and the mappings don't tell how the system switches the
+    * banks. */
+
+   /* TODO: When finalizing this one, fix the 'len' bit removal order.
+    * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.
+    * Algorithm: Take bits highest to lowest, but if it goes above len, clear
+    * the most recent addition and continue on the next bit.
+    * TODO: Can the above be optimized? Is "remove the lowest bit set in both
+    * pointer and 'len'" equivalent? */
+
+   /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing
+    * the emulated memory in 32-bit chunks, native endian. But that's nothing
+    * compared to Darek Mihocka <http://www.emulators.com/docs/nx07_vm101.htm>
+    * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE
+    * RAM backwards! I'll want to represent both of those, via some flags.
+    *
+    * I suspect MAME either didn't think of that idea, or don't want the #ifdef.
+    * Not sure which, nor do I really care. */
+
+   /* TODO: Some of those flags are unused and/or don't really make sense. Clean
+    * them up. */
+};
+
+/* The frontend may use the largest value of 'start'+'select' in a
+ * certain namespace to infer the size of the address space.
+ *
+ * If the address space is larger than that, a mapping with .ptr=NULL
+ * should be at the end of the array, with .select set to all ones for
+ * as long as the address space is big.
+ *
+ * Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags):
+ * SNES WRAM:
+ * .start=0x7E0000, .len=0x20000
+ * (Note that this must be mapped before the ROM in most cases; some of the
+ * ROM mappers
+ * try to claim $7E0000, or at least $7E8000.)
+ * SNES SPC700 RAM:
+ * .addrspace="S", .len=0x10000
+ * SNES WRAM mirrors:
+ * .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000
+ * .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000
+ * SNES WRAM mirrors, alternate equivalent descriptor:
+ * .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF
+ * (Various similar constructions can be created by combining parts of
+ * the above two.)
+ * SNES LoROM (512KB, mirrored a couple of times):
+ * .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024
+ * .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024
+ * SNES HiROM (4MB):
+ * .flags=CONST,                 .start=0x400000, .select=0x400000, .len=4*1024*1024
+ * .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024
+ * SNES ExHiROM (8MB):
+ * .flags=CONST, .offset=0,                  .start=0xC00000, .select=0xC00000, .len=4*1024*1024
+ * .flags=CONST, .offset=4*1024*1024,        .start=0x400000, .select=0xC00000, .len=4*1024*1024
+ * .flags=CONST, .offset=0x8000,             .start=0x808000, .select=0xC08000, .len=4*1024*1024
+ * .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024
+ * Clarify the size of the address space:
+ * .ptr=NULL, .select=0xFFFFFF
+ * .len can be implied by .select in many of them, but was included for clarity.
+ */
+
+struct retro_memory_map
+{
+   const struct retro_memory_descriptor *descriptors;
+   unsigned num_descriptors;
+};
+
+struct retro_controller_description
+{
+   /* Human-readable description of the controller. Even if using a generic
+    * input device type, this can be set to the particular device type the
+    * core uses. */
+   const char *desc;
+
+   /* Device type passed to retro_set_controller_port_device(). If the device
+    * type is a sub-class of a generic input device type, use the
+    * RETRO_DEVICE_SUBCLASS macro to create an ID.
+    *
+    * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */
+   unsigned id;
+};
+
+struct retro_controller_info
+{
+   const struct retro_controller_description *types;
+   unsigned num_types;
+};
+
+struct retro_subsystem_memory_info
+{
+   /* The extension associated with a memory type, e.g. "psram". */
+   const char *extension;
+
+   /* The memory type for retro_get_memory(). This should be at
+    * least 0x100 to avoid conflict with standardized
+    * libretro memory types. */
+   unsigned type;
+};
+
+struct retro_subsystem_rom_info
+{
+   /* Describes what the content is (SGB BIOS, GB ROM, etc). */
+   const char *desc;
+
+   /* Same definition as retro_get_system_info(). */
+   const char *valid_extensions;
+
+   /* Same definition as retro_get_system_info(). */
+   bool need_fullpath;
+
+   /* Same definition as retro_get_system_info(). */
+   bool block_extract;
+
+   /* This is set if the content is required to load a game.
+    * If this is set to false, a zeroed-out retro_game_info can be passed. */
+   bool required;
+
+   /* Content can have multiple associated persistent
+    * memory types (retro_get_memory()). */
+   const struct retro_subsystem_memory_info *memory;
+   unsigned num_memory;
+};
+
+struct retro_subsystem_info
+{
+   /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */
+   const char *desc;
+
+   /* A computer friendly short string identifier for the subsystem type.
+    * This name must be [a-z].
+    * E.g. if desc is "Super GameBoy", this can be "sgb".
+    * This identifier can be used for command-line interfaces, etc.
+    */
+   const char *ident;
+
+   /* Infos for each content file. The first entry is assumed to be the
+    * "most significant" content for frontend purposes.
+    * E.g. with Super GameBoy, the first content should be the GameBoy ROM,
+    * as it is the most "significant" content to a user.
+    * If a frontend creates new file paths based on the content used
+    * (e.g. savestates), it should use the path for the first ROM to do so. */
+   const struct retro_subsystem_rom_info *roms;
+
+   /* Number of content files associated with a subsystem. */
+   unsigned num_roms;
+
+   /* The type passed to retro_load_game_special(). */
+   unsigned id;
+};
+
+typedef void (RETRO_CALLCONV *retro_proc_address_t)(void);
+
+/* libretro API extension functions:
+ * (None here so far).
+ *
+ * Get a symbol from a libretro core.
+ * Cores should only return symbols which are actual
+ * extensions to the libretro API.
+ *
+ * Frontends should not use this to obtain symbols to standard
+ * libretro entry points (static linking or dlsym).
+ *
+ * The symbol name must be equal to the function name,
+ * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo".
+ * The returned function pointer must be cast to the corresponding type.
+ */
+typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);
+
+struct retro_get_proc_address_interface
+{
+   retro_get_proc_address_t get_proc_address;
+};
+
+enum retro_log_level
+{
+   RETRO_LOG_DEBUG = 0,
+   RETRO_LOG_INFO,
+   RETRO_LOG_WARN,
+   RETRO_LOG_ERROR,
+
+   RETRO_LOG_DUMMY = INT_MAX
+};
+
+/* Logging function. Takes log level argument as well. */
+typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,
+      const char *fmt, ...);
+
+struct retro_log_callback
+{
+   retro_log_printf_t log;
+};
+
+/* Performance related functions */
+
+/* ID values for SIMD CPU features */
+#define RETRO_SIMD_SSE      (1 << 0)
+#define RETRO_SIMD_SSE2     (1 << 1)
+#define RETRO_SIMD_VMX      (1 << 2)
+#define RETRO_SIMD_VMX128   (1 << 3)
+#define RETRO_SIMD_AVX      (1 << 4)
+#define RETRO_SIMD_NEON     (1 << 5)
+#define RETRO_SIMD_SSE3     (1 << 6)
+#define RETRO_SIMD_SSSE3    (1 << 7)
+#define RETRO_SIMD_MMX      (1 << 8)
+#define RETRO_SIMD_MMXEXT   (1 << 9)
+#define RETRO_SIMD_SSE4     (1 << 10)
+#define RETRO_SIMD_SSE42    (1 << 11)
+#define RETRO_SIMD_AVX2     (1 << 12)
+#define RETRO_SIMD_VFPU     (1 << 13)
+#define RETRO_SIMD_PS       (1 << 14)
+#define RETRO_SIMD_AES      (1 << 15)
+#define RETRO_SIMD_VFPV3    (1 << 16)
+#define RETRO_SIMD_VFPV4    (1 << 17)
+#define RETRO_SIMD_POPCNT   (1 << 18)
+#define RETRO_SIMD_MOVBE    (1 << 19)
+#define RETRO_SIMD_CMOV     (1 << 20)
+#define RETRO_SIMD_ASIMD    (1 << 21)
+
+typedef uint64_t retro_perf_tick_t;
+typedef int64_t retro_time_t;
+
+struct retro_perf_counter
+{
+   const char *ident;
+   retro_perf_tick_t start;
+   retro_perf_tick_t total;
+   retro_perf_tick_t call_cnt;
+
+   bool registered;
+};
+
+/* Returns current time in microseconds.
+ * Tries to use the most accurate timer available.
+ */
+typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);
+
+/* A simple counter. Usually nanoseconds, but can also be CPU cycles.
+ * Can be used directly if desired (when creating a more sophisticated
+ * performance counter system).
+ * */
+typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);
+
+/* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */
+typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);
+
+/* Asks frontend to log and/or display the state of performance counters.
+ * Performance counters can always be poked into manually as well.
+ */
+typedef void (RETRO_CALLCONV *retro_perf_log_t)(void);
+
+/* Register a performance counter.
+ * ident field must be set with a discrete value and other values in
+ * retro_perf_counter must be 0.
+ * Registering can be called multiple times. To avoid calling to
+ * frontend redundantly, you can check registered field first. */
+typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);
+
+/* Starts a registered counter. */
+typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);
+
+/* Stops a registered counter. */
+typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);
+
+/* For convenience it can be useful to wrap register, start and stop in macros.
+ * E.g.:
+ * #ifdef LOG_PERFORMANCE
+ * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
+ * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))
+ * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))
+ * #else
+ * ... Blank macros ...
+ * #endif
+ *
+ * These can then be used mid-functions around code snippets.
+ *
+ * extern struct retro_perf_callback perf_cb;  * Somewhere in the core.
+ *
+ * void do_some_heavy_work(void)
+ * {
+ *    RETRO_PERFORMANCE_INIT(cb, work_1;
+ *    RETRO_PERFORMANCE_START(cb, work_1);
+ *    heavy_work_1();
+ *    RETRO_PERFORMANCE_STOP(cb, work_1);
+ *
+ *    RETRO_PERFORMANCE_INIT(cb, work_2);
+ *    RETRO_PERFORMANCE_START(cb, work_2);
+ *    heavy_work_2();
+ *    RETRO_PERFORMANCE_STOP(cb, work_2);
+ * }
+ *
+ * void retro_deinit(void)
+ * {
+ *    perf_cb.perf_log();  * Log all perf counters here for example.
+ * }
+ */
+
+struct retro_perf_callback
+{
+   retro_perf_get_time_usec_t    get_time_usec;
+   retro_get_cpu_features_t      get_cpu_features;
+
+   retro_perf_get_counter_t      get_perf_counter;
+   retro_perf_register_t         perf_register;
+   retro_perf_start_t            perf_start;
+   retro_perf_stop_t             perf_stop;
+   retro_perf_log_t              perf_log;
+};
+
+/* FIXME: Document the sensor API and work out behavior.
+ * It will be marked as experimental until then.
+ */
+enum retro_sensor_action
+{
+   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,
+   RETRO_SENSOR_ACCELEROMETER_DISABLE,
+   RETRO_SENSOR_GYROSCOPE_ENABLE,
+   RETRO_SENSOR_GYROSCOPE_DISABLE,
+   RETRO_SENSOR_ILLUMINANCE_ENABLE,
+   RETRO_SENSOR_ILLUMINANCE_DISABLE,
+
+   RETRO_SENSOR_DUMMY = INT_MAX
+};
+
+/* Id values for SENSOR types. */
+#define RETRO_SENSOR_ACCELEROMETER_X 0
+#define RETRO_SENSOR_ACCELEROMETER_Y 1
+#define RETRO_SENSOR_ACCELEROMETER_Z 2
+#define RETRO_SENSOR_GYROSCOPE_X 3
+#define RETRO_SENSOR_GYROSCOPE_Y 4
+#define RETRO_SENSOR_GYROSCOPE_Z 5
+#define RETRO_SENSOR_ILLUMINANCE 6
+
+typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
+      enum retro_sensor_action action, unsigned rate);
+
+typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);
+
+struct retro_sensor_interface
+{
+   retro_set_sensor_state_t set_sensor_state;
+   retro_sensor_get_input_t get_sensor_input;
+};
+
+enum retro_camera_buffer
+{
+   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,
+   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,
+
+   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
+};
+
+/* Starts the camera driver. Can only be called in retro_run(). */
+typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);
+
+/* Stops the camera driver. Can only be called in retro_run(). */
+typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);
+
+/* Callback which signals when the camera driver is initialized
+ * and/or deinitialized.
+ * retro_camera_start_t can be called in initialized callback.
+ */
+typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);
+
+/* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer.
+ * Width, height and pitch are similar to retro_video_refresh_t.
+ * First pixel is top-left origin.
+ */
+typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
+      unsigned width, unsigned height, size_t pitch);
+
+/* A callback for when OpenGL textures are used.
+ *
+ * texture_id is a texture owned by camera driver.
+ * Its state or content should be considered immutable, except for things like
+ * texture filtering and clamping.
+ *
+ * texture_target is the texture target for the GL texture.
+ * These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly
+ * more depending on extensions.
+ *
+ * affine points to a packed 3x3 column-major matrix used to apply an affine
+ * transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0))
+ * After transform, normalized texture coord (0, 0) should be bottom-left
+ * and (1, 1) should be top-right (or (width, height) for RECTANGLE).
+ *
+ * GL-specific typedefs are avoided here to avoid relying on gl.h in
+ * the API definition.
+ */
+typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,
+      unsigned texture_target, const float *affine);
+
+struct retro_camera_callback
+{
+   /* Set by libretro core.
+    * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER).
+    */
+   uint64_t caps;
+
+   /* Desired resolution for camera. Is only used as a hint. */
+   unsigned width;
+   unsigned height;
+
+   /* Set by frontend. */
+   retro_camera_start_t start;
+   retro_camera_stop_t stop;
+
+   /* Set by libretro core if raw framebuffer callbacks will be used. */
+   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;
+
+   /* Set by libretro core if OpenGL texture callbacks will be used. */
+   retro_camera_frame_opengl_texture_t frame_opengl_texture;
+
+   /* Set by libretro core. Called after camera driver is initialized and
+    * ready to be started.
+    * Can be NULL, in which this callback is not called.
+    */
+   retro_camera_lifetime_status_t initialized;
+
+   /* Set by libretro core. Called right before camera driver is
+    * deinitialized.
+    * Can be NULL, in which this callback is not called.
+    */
+   retro_camera_lifetime_status_t deinitialized;
+};
+
+/* Sets the interval of time and/or distance at which to update/poll
+ * location-based data.
+ *
+ * To ensure compatibility with all location-based implementations,
+ * values for both interval_ms and interval_distance should be provided.
+ *
+ * interval_ms is the interval expressed in milliseconds.
+ * interval_distance is the distance interval expressed in meters.
+ */
+typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,
+      unsigned interval_distance);
+
+/* Start location services. The device will start listening for changes to the
+ * current location at regular intervals (which are defined with
+ * retro_location_set_interval_t). */
+typedef bool (RETRO_CALLCONV *retro_location_start_t)(void);
+
+/* Stop location services. The device will stop listening for changes
+ * to the current location. */
+typedef void (RETRO_CALLCONV *retro_location_stop_t)(void);
+
+/* Get the position of the current location. Will set parameters to
+ * 0 if no new  location update has happened since the last time. */
+typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,
+      double *horiz_accuracy, double *vert_accuracy);
+
+/* Callback which signals when the location driver is initialized
+ * and/or deinitialized.
+ * retro_location_start_t can be called in initialized callback.
+ */
+typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);
+
+struct retro_location_callback
+{
+   retro_location_start_t         start;
+   retro_location_stop_t          stop;
+   retro_location_get_position_t  get_position;
+   retro_location_set_interval_t  set_interval;
+
+   retro_location_lifetime_status_t initialized;
+   retro_location_lifetime_status_t deinitialized;
+};
+
+enum retro_rumble_effect
+{
+   RETRO_RUMBLE_STRONG = 0,
+   RETRO_RUMBLE_WEAK = 1,
+
+   RETRO_RUMBLE_DUMMY = INT_MAX
+};
+
+/* Sets rumble state for joypad plugged in port 'port'.
+ * Rumble effects are controlled independently,
+ * and setting e.g. strong rumble does not override weak rumble.
+ * Strength has a range of [0, 0xffff].
+ *
+ * Returns true if rumble state request was honored.
+ * Calling this before first retro_run() is likely to return false. */
+typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,
+      enum retro_rumble_effect effect, uint16_t strength);
+
+struct retro_rumble_interface
+{
+   retro_set_rumble_state_t set_rumble_state;
+};
+
+/* Notifies libretro that audio data should be written. */
+typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);
+
+/* True: Audio driver in frontend is active, and callback is
+ * expected to be called regularily.
+ * False: Audio driver in frontend is paused or inactive.
+ * Audio callback will not be called until set_state has been
+ * called with true.
+ * Initial state is false (inactive).
+ */
+typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);
+
+struct retro_audio_callback
+{
+   retro_audio_callback_t callback;
+   retro_audio_set_state_callback_t set_state;
+};
+
+/* Notifies a libretro core of time spent since last invocation
+ * of retro_run() in microseconds.
+ *
+ * It will be called right before retro_run() every frame.
+ * The frontend can tamper with timing to support cases like
+ * fast-forward, slow-motion and framestepping.
+ *
+ * In those scenarios the reference frame time value will be used. */
+typedef int64_t retro_usec_t;
+typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);
+struct retro_frame_time_callback
+{
+   retro_frame_time_callback_t callback;
+   /* Represents the time of one frame. It is computed as
+    * 1000000 / fps, but the implementation will resolve the
+    * rounding to ensure that framestepping, etc is exact. */
+   retro_usec_t reference;
+};
+
+/* Notifies a libretro core of the current occupancy
+ * level of the frontend audio buffer.
+ *
+ * - active: 'true' if audio buffer is currently
+ *           in use. Will be 'false' if audio is
+ *           disabled in the frontend
+ *
+ * - occupancy: Given as a value in the range [0,100],
+ *              corresponding to the occupancy percentage
+ *              of the audio buffer
+ *
+ * - underrun_likely: 'true' if the frontend expects an
+ *                    audio buffer underrun during the
+ *                    next frame (indicates that a core
+ *                    should attempt frame skipping)
+ *
+ * It will be called right before retro_run() every frame. */
+typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
+      bool active, unsigned occupancy, bool underrun_likely);
+struct retro_audio_buffer_status_callback
+{
+   retro_audio_buffer_status_callback_t callback;
+};
+
+/* Pass this to retro_video_refresh_t if rendering to hardware.
+ * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
+ * */
+#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)
+
+/* Invalidates the current HW context.
+ * Any GL state is lost, and must not be deinitialized explicitly.
+ * If explicit deinitialization is desired by the libretro core,
+ * it should implement context_destroy callback.
+ * If called, all GPU resources must be reinitialized.
+ * Usually called when frontend reinits video driver.
+ * Also called first time video driver is initialized,
+ * allowing libretro core to initialize resources.
+ */
+typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);
+
+/* Gets current framebuffer which is to be rendered to.
+ * Could change every frame potentially.
+ */
+typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);
+
+/* Get a symbol from HW context. */
+typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);
+
+enum retro_hw_context_type
+{
+   RETRO_HW_CONTEXT_NONE             = 0,
+   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
+   RETRO_HW_CONTEXT_OPENGL           = 1,
+   /* OpenGL ES 2.0. */
+   RETRO_HW_CONTEXT_OPENGLES2        = 2,
+   /* Modern desktop core GL context. Use version_major/
+    * version_minor fields to set GL version. */
+   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,
+   /* OpenGL ES 3.0 */
+   RETRO_HW_CONTEXT_OPENGLES3        = 4,
+   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
+    * use the corresponding enums directly. */
+   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,
+
+   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
+   RETRO_HW_CONTEXT_VULKAN           = 6,
+
+   /* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
+   RETRO_HW_CONTEXT_D3D11            = 7,
+
+   /* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
+   RETRO_HW_CONTEXT_D3D10            = 8,
+
+   /* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
+   RETRO_HW_CONTEXT_D3D12            = 9,
+
+   /* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
+   RETRO_HW_CONTEXT_D3D9             = 10,
+
+   RETRO_HW_CONTEXT_DUMMY = INT_MAX
+};
+
+struct retro_hw_render_callback
+{
+   /* Which API to use. Set by libretro core. */
+   enum retro_hw_context_type context_type;
+
+   /* Called when a context has been created or when it has been reset.
+    * An OpenGL context is only valid after context_reset() has been called.
+    *
+    * When context_reset is called, OpenGL resources in the libretro
+    * implementation are guaranteed to be invalid.
+    *
+    * It is possible that context_reset is called multiple times during an
+    * application lifecycle.
+    * If context_reset is called without any notification (context_destroy),
+    * the OpenGL context was lost and resources should just be recreated
+    * without any attempt to "free" old resources.
+    */
+   retro_hw_context_reset_t context_reset;
+
+   /* Set by frontend.
+    * TODO: This is rather obsolete. The frontend should not
+    * be providing preallocated framebuffers. */
+   retro_hw_get_current_framebuffer_t get_current_framebuffer;
+
+   /* Set by frontend.
+    * Can return all relevant functions, including glClear on Windows. */
+   retro_hw_get_proc_address_t get_proc_address;
+
+   /* Set if render buffers should have depth component attached.
+    * TODO: Obsolete. */
+   bool depth;
+
+   /* Set if stencil buffers should be attached.
+    * TODO: Obsolete. */
+   bool stencil;
+
+   /* If depth and stencil are true, a packed 24/8 buffer will be added.
+    * Only attaching stencil is invalid and will be ignored. */
+
+   /* Use conventional bottom-left origin convention. If false,
+    * standard libretro top-left origin semantics are used.
+    * TODO: Move to GL specific interface. */
+   bool bottom_left_origin;
+
+   /* Major version number for core GL context or GLES 3.1+. */
+   unsigned version_major;
+
+   /* Minor version number for core GL context or GLES 3.1+. */
+   unsigned version_minor;
+
+   /* If this is true, the frontend will go very far to avoid
+    * resetting context in scenarios like toggling fullscreen, etc.
+    * TODO: Obsolete? Maybe frontend should just always assume this ...
+    */
+   bool cache_context;
+
+   /* The reset callback might still be called in extreme situations
+    * such as if the context is lost beyond recovery.
+    *
+    * For optimal stability, set this to false, and allow context to be
+    * reset at any time.
+    */
+
+   /* A callback to be called before the context is destroyed in a
+    * controlled way by the frontend. */
+   retro_hw_context_reset_t context_destroy;
+
+   /* OpenGL resources can be deinitialized cleanly at this step.
+    * context_destroy can be set to NULL, in which resources will
+    * just be destroyed without any notification.
+    *
+    * Even when context_destroy is non-NULL, it is possible that
+    * context_reset is called without any destroy notification.
+    * This happens if context is lost by external factors (such as
+    * notified by GL_ARB_robustness).
+    *
+    * In this case, the context is assumed to be already dead,
+    * and the libretro implementation must not try to free any OpenGL
+    * resources in the subsequent context_reset.
+    */
+
+   /* Creates a debug context. */
+   bool debug_context;
+};
+
+/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
+ * Called by the frontend in response to keyboard events.
+ * down is set if the key is being pressed, or false if it is being released.
+ * keycode is the RETROK value of the char.
+ * character is the text character of the pressed key. (UTF-32).
+ * key_modifiers is a set of RETROKMOD values or'ed together.
+ *
+ * The pressed/keycode state can be indepedent of the character.
+ * It is also possible that multiple characters are generated from a
+ * single keypress.
+ * Keycode events should be treated separately from character events.
+ * However, when possible, the frontend should try to synchronize these.
+ * If only a character is posted, keycode should be RETROK_UNKNOWN.
+ *
+ * Similarily if only a keycode event is generated with no corresponding
+ * character, character should be 0.
+ */
+typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,
+      uint32_t character, uint16_t key_modifiers);
+
+struct retro_keyboard_callback
+{
+   retro_keyboard_event_t callback;
+};
+
+/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE &
+ * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
+ * Should be set for implementations which can swap out multiple disk
+ * images in runtime.
+ *
+ * If the implementation can do this automatically, it should strive to do so.
+ * However, there are cases where the user must manually do so.
+ *
+ * Overview: To swap a disk image, eject the disk image with
+ * set_eject_state(true).
+ * Set the disk index with set_image_index(index). Insert the disk again
+ * with set_eject_state(false).
+ */
+
+/* If ejected is true, "ejects" the virtual disk tray.
+ * When ejected, the disk image index can be set.
+ */
+typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);
+
+/* Gets current eject state. The initial state is 'not ejected'. */
+typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);
+
+/* Gets current disk index. First disk is index 0.
+ * If return value is >= get_num_images(), no disk is currently inserted.
+ */
+typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);
+
+/* Sets image index. Can only be called when disk is ejected.
+ * The implementation supports setting "no disk" by using an
+ * index >= get_num_images().
+ */
+typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);
+
+/* Gets total number of images which are available to use. */
+typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);
+
+struct retro_game_info;
+
+/* Replaces the disk image associated with index.
+ * Arguments to pass in info have same requirements as retro_load_game().
+ * Virtual disk tray must be ejected when calling this.
+ *
+ * Replacing a disk image with info = NULL will remove the disk image
+ * from the internal list.
+ * As a result, calls to get_image_index() can change.
+ *
+ * E.g. replace_image_index(1, NULL), and previous get_image_index()
+ * returned 4 before.
+ * Index 1 will be removed, and the new index is 3.
+ */
+typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
+      const struct retro_game_info *info);
+
+/* Adds a new valid index (get_num_images()) to the internal disk list.
+ * This will increment subsequent return values from get_num_images() by 1.
+ * This image index cannot be used until a disk image has been set
+ * with replace_image_index. */
+typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);
+
+/* Sets initial image to insert in drive when calling
+ * core_load_game().
+ * Since we cannot pass the initial index when loading
+ * content (this would require a major API change), this
+ * is set by the frontend *before* calling the core's
+ * retro_load_game()/retro_load_game_special() implementation.
+ * A core should therefore cache the index/path values and handle
+ * them inside retro_load_game()/retro_load_game_special().
+ * - If 'index' is invalid (index >= get_num_images()), the
+ *   core should ignore the set value and instead use 0
+ * - 'path' is used purely for error checking - i.e. when
+ *   content is loaded, the core should verify that the
+ *   disk specified by 'index' has the specified file path.
+ *   This is to guard against auto selecting the wrong image
+ *   if (for example) the user should modify an existing M3U
+ *   playlist. We have to let the core handle this because
+ *   set_initial_image() must be called before loading content,
+ *   i.e. the frontend cannot access image paths in advance
+ *   and thus cannot perform the error check itself.
+ *   If set path and content path do not match, the core should
+ *   ignore the set 'index' value and instead use 0
+ * Returns 'false' if index or 'path' are invalid, or core
+ * does not support this functionality
+ */
+typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);
+
+/* Fetches the path of the specified disk image file.
+ * Returns 'false' if index is invalid (index >= get_num_images())
+ * or path is otherwise unavailable.
+ */
+typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len);
+
+/* Fetches a core-provided 'label' for the specified disk
+ * image file. In the simplest case this may be a file name
+ * (without extension), but for cores with more complex
+ * content requirements information may be provided to
+ * facilitate user disk swapping - for example, a core
+ * running floppy-disk-based content may uniquely label
+ * save disks, data disks, level disks, etc. with names
+ * corresponding to in-game disk change prompts (so the
+ * frontend can provide better user guidance than a 'dumb'
+ * disk index value).
+ * Returns 'false' if index is invalid (index >= get_num_images())
+ * or label is otherwise unavailable.
+ */
+typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len);
+
+struct retro_disk_control_callback
+{
+   retro_set_eject_state_t set_eject_state;
+   retro_get_eject_state_t get_eject_state;
+
+   retro_get_image_index_t get_image_index;
+   retro_set_image_index_t set_image_index;
+   retro_get_num_images_t  get_num_images;
+
+   retro_replace_image_index_t replace_image_index;
+   retro_add_image_index_t add_image_index;
+};
+
+struct retro_disk_control_ext_callback
+{
+   retro_set_eject_state_t set_eject_state;
+   retro_get_eject_state_t get_eject_state;
+
+   retro_get_image_index_t get_image_index;
+   retro_set_image_index_t set_image_index;
+   retro_get_num_images_t  get_num_images;
+
+   retro_replace_image_index_t replace_image_index;
+   retro_add_image_index_t add_image_index;
+
+   /* NOTE: Frontend will only attempt to record/restore
+    * last used disk index if both set_initial_image()
+    * and get_image_path() are implemented */
+   retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */
+
+   retro_get_image_path_t get_image_path;       /* Optional - may be NULL */
+   retro_get_image_label_t get_image_label;     /* Optional - may be NULL */
+};
+
+enum retro_pixel_format
+{
+   /* 0RGB1555, native endian.
+    * 0 bit must be set to 0.
+    * This pixel format is default for compatibility concerns only.
+    * If a 15/16-bit pixel format is desired, consider using RGB565. */
+   RETRO_PIXEL_FORMAT_0RGB1555 = 0,
+
+   /* XRGB8888, native endian.
+    * X bits are ignored. */
+   RETRO_PIXEL_FORMAT_XRGB8888 = 1,
+
+   /* RGB565, native endian.
+    * This pixel format is the recommended format to use if a 15/16-bit
+    * format is desired as it is the pixel format that is typically
+    * available on a wide range of low-power devices.
+    *
+    * It is also natively supported in APIs like OpenGL ES. */
+   RETRO_PIXEL_FORMAT_RGB565   = 2,
+
+   /* Ensure sizeof() == sizeof(int). */
+   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX
+};
+
+enum retro_savestate_context
+{
+   /* Standard savestate written to disk. */
+   RETRO_SAVESTATE_CONTEXT_NORMAL                 = 0,
+
+   /* Savestate where you are guaranteed that the same instance will load the save state.
+    * You can store internal pointers to code or data.
+    * It's still a full serialization and deserialization, and could be loaded or saved at any time. 
+    * It won't be written to disk or sent over the network.
+    */
+   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,
+
+   /* Savestate where you are guaranteed that the same emulator binary will load that savestate.
+    * You can skip anything that would slow down saving or loading state but you can not store internal pointers. 
+    * It won't be written to disk or sent over the network.
+    * Example: "Second Instance" runahead
+    */
+   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY   = 2,
+
+   /* Savestate used within a rollback netplay feature.
+    * You should skip anything that would unnecessarily increase bandwidth usage.
+    * It won't be written to disk but it will be sent over the network.
+    */
+   RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY       = 3,
+
+   /* Ensure sizeof() == sizeof(int). */
+   RETRO_SAVESTATE_CONTEXT_UNKNOWN                = INT_MAX
+};
+
+struct retro_message
+{
+   const char *msg;        /* Message to be displayed. */
+   unsigned    frames;     /* Duration in frames of message. */
+};
+
+enum retro_message_target
+{
+   RETRO_MESSAGE_TARGET_ALL = 0,
+   RETRO_MESSAGE_TARGET_OSD,
+   RETRO_MESSAGE_TARGET_LOG
+};
+
+enum retro_message_type
+{
+   RETRO_MESSAGE_TYPE_NOTIFICATION = 0,
+   RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
+   RETRO_MESSAGE_TYPE_STATUS,
+   RETRO_MESSAGE_TYPE_PROGRESS
+};
+
+struct retro_message_ext
+{
+   /* Message string to be displayed/logged */
+   const char *msg;
+   /* Duration (in ms) of message when targeting the OSD */
+   unsigned duration;
+   /* Message priority when targeting the OSD
+    * > When multiple concurrent messages are sent to
+    *   the frontend and the frontend does not have the
+    *   capacity to display them all, messages with the
+    *   *highest* priority value should be shown
+    * > There is no upper limit to a message priority
+    *   value (within the bounds of the unsigned data type)
+    * > In the reference frontend (RetroArch), the same
+    *   priority values are used for frontend-generated
+    *   notifications, which are typically assigned values
+    *   between 0 and 3 depending upon importance */
+   unsigned priority;
+   /* Message logging level (info, warn, error, etc.) */
+   enum retro_log_level level;
+   /* Message destination: OSD, logging interface or both */
+   enum retro_message_target target;
+   /* Message 'type' when targeting the OSD
+    * > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a
+    *   message should be handled in identical fashion to
+    *   a standard frontend-generated notification
+    * > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that
+    *   message is a notification that requires user attention
+    *   or action, but that it should be displayed in a manner
+    *   that differs from standard frontend-generated notifications.
+    *   This would typically correspond to messages that should be
+    *   displayed immediately (independently from any internal
+    *   frontend message queue), and/or which should be visually
+    *   distinguishable from frontend-generated notifications.
+    *   For example, a core may wish to inform the user of
+    *   information related to a disk-change event. It is
+    *   expected that the frontend itself may provide a
+    *   notification in this case; if the core sends a
+    *   message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an
+    *   uncomfortable 'double-notification' may occur. A message
+    *   of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore
+    *   be presented such that visual conflict with regular
+    *   notifications does not occur
+    * > RETRO_MESSAGE_TYPE_STATUS: Indicates that message
+    *   is not a standard notification. This typically
+    *   corresponds to 'status' indicators, such as a core's
+    *   internal FPS, which are intended to be displayed
+    *   either permanently while a core is running, or in
+    *   a manner that does not suggest user attention or action
+    *   is required. 'Status' type messages should therefore be
+    *   displayed in a different on-screen location and in a manner
+    *   easily distinguishable from both standard frontend-generated
+    *   notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT
+    * > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports
+    *   the progress of an internal core task. For example, in cases
+    *   where a core itself handles the loading of content from a file,
+    *   this may correspond to the percentage of the file that has been
+    *   read. Alternatively, an audio/video playback core may use a
+    *   message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current
+    *   playback position as a percentage of the runtime. 'Progress' type
+    *   messages should therefore be displayed as a literal progress bar,
+    *   where:
+    *   - 'retro_message_ext.msg' is the progress bar title/label
+    *   - 'retro_message_ext.progress' determines the length of
+    *     the progress bar
+    * NOTE: Message type is a *hint*, and may be ignored
+    * by the frontend. If a frontend lacks support for
+    * displaying messages via alternate means than standard
+    * frontend-generated notifications, it will treat *all*
+    * messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */
+   enum retro_message_type type;
+   /* Task progress when targeting the OSD and message is
+    * of type RETRO_MESSAGE_TYPE_PROGRESS
+    * > -1:    Unmetered/indeterminate
+    * > 0-100: Current progress percentage
+    * NOTE: Since message type is a hint, a frontend may ignore
+    * progress values. Where relevant, a core should therefore
+    * include progress percentage within the message string,
+    * such that the message intent remains clear when displayed
+    * as a standard frontend-generated notification */
+   int8_t progress;
+};
+
+/* Describes how the libretro implementation maps a libretro input bind
+ * to its internal input system through a human readable string.
+ * This string can be used to better let a user configure input. */
+struct retro_input_descriptor
+{
+   /* Associates given parameters with a description. */
+   unsigned port;
+   unsigned device;
+   unsigned index;
+   unsigned id;
+
+   /* Human readable description for parameters.
+    * The pointer must remain valid until
+    * retro_unload_game() is called. */
+   const char *description;
+};
+
+struct retro_system_info
+{
+   /* All pointers are owned by libretro implementation, and pointers must
+    * remain valid until it is unloaded. */
+
+   const char *library_name;      /* Descriptive name of library. Should not
+                                   * contain any version numbers, etc. */
+   const char *library_version;   /* Descriptive version of core. */
+
+   const char *valid_extensions;  /* A string listing probably content
+                                   * extensions the core will be able to
+                                   * load, separated with pipe.
+                                   * I.e. "bin|rom|iso".
+                                   * Typically used for a GUI to filter
+                                   * out extensions. */
+
+   /* Libretro cores that need to have direct access to their content
+    * files, including cores which use the path of the content files to
+    * determine the paths of other files, should set need_fullpath to true.
+    *
+    * Cores should strive for setting need_fullpath to false,
+    * as it allows the frontend to perform patching, etc.
+    *
+    * If need_fullpath is true and retro_load_game() is called:
+    *    - retro_game_info::path is guaranteed to have a valid path
+    *    - retro_game_info::data and retro_game_info::size are invalid
+    *
+    * If need_fullpath is false and retro_load_game() is called:
+    *    - retro_game_info::path may be NULL
+    *    - retro_game_info::data and retro_game_info::size are guaranteed
+    *      to be valid
+    *
+    * See also:
+    *    - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
+    *    - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
+    */
+   bool        need_fullpath;
+
+   /* If true, the frontend is not allowed to extract any archives before
+    * loading the real content.
+    * Necessary for certain libretro implementations that load games
+    * from zipped archives. */
+   bool        block_extract;
+};
+
+/* Defines overrides which modify frontend handling of
+ * specific content file types.
+ * An array of retro_system_content_info_override is
+ * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE
+ * NOTE: In the following descriptions, references to
+ *       retro_load_game() may be replaced with
+ *       retro_load_game_special() */
+struct retro_system_content_info_override
+{
+   /* A list of file extensions for which the override
+    * should apply, delimited by a 'pipe' character
+    * (e.g. "md|sms|gg")
+    * Permitted file extensions are limited to those
+    * included in retro_system_info::valid_extensions
+    * and/or retro_subsystem_rom_info::valid_extensions */
+   const char *extensions;
+
+   /* Overrides the need_fullpath value set in
+    * retro_system_info and/or retro_subsystem_rom_info.
+    * To reiterate:
+    *
+    * If need_fullpath is true and retro_load_game() is called:
+    *    - retro_game_info::path is guaranteed to contain a valid
+    *      path to an existent file
+    *    - retro_game_info::data and retro_game_info::size are invalid
+    *
+    * If need_fullpath is false and retro_load_game() is called:
+    *    - retro_game_info::path may be NULL
+    *    - retro_game_info::data and retro_game_info::size are guaranteed
+    *      to be valid
+    *
+    * In addition:
+    *
+    * If need_fullpath is true and retro_load_game() is called:
+    *    - retro_game_info_ext::full_path is guaranteed to contain a valid
+    *      path to an existent file
+    *    - retro_game_info_ext::archive_path may be NULL
+    *    - retro_game_info_ext::archive_file may be NULL
+    *    - retro_game_info_ext::dir is guaranteed to contain a valid path
+    *      to the directory in which the content file exists
+    *    - retro_game_info_ext::name is guaranteed to contain the
+    *      basename of the content file, without extension
+    *    - retro_game_info_ext::ext is guaranteed to contain the
+    *      extension of the content file in lower case format
+    *    - retro_game_info_ext::data and retro_game_info_ext::size
+    *      are invalid
+    *
+    * If need_fullpath is false and retro_load_game() is called:
+    *    - If retro_game_info_ext::file_in_archive is false:
+    *       - retro_game_info_ext::full_path is guaranteed to contain
+    *         a valid path to an existent file
+    *       - retro_game_info_ext::archive_path may be NULL
+    *       - retro_game_info_ext::archive_file may be NULL
+    *       - retro_game_info_ext::dir is guaranteed to contain a
+    *         valid path to the directory in which the content file exists
+    *       - retro_game_info_ext::name is guaranteed to contain the
+    *         basename of the content file, without extension
+    *       - retro_game_info_ext::ext is guaranteed to contain the
+    *         extension of the content file in lower case format
+    *    - If retro_game_info_ext::file_in_archive is true:
+    *       - retro_game_info_ext::full_path may be NULL
+    *       - retro_game_info_ext::archive_path is guaranteed to
+    *         contain a valid path to an existent compressed file
+    *         inside which the content file is located
+    *       - retro_game_info_ext::archive_file is guaranteed to
+    *         contain a valid path to an existent content file
+    *         inside the compressed file referred to by
+    *         retro_game_info_ext::archive_path
+    *            e.g. for a compressed file '/path/to/foo.zip'
+    *            containing 'bar.sfc'
+    *             > retro_game_info_ext::archive_path will be '/path/to/foo.zip'
+    *             > retro_game_info_ext::archive_file will be 'bar.sfc'
+    *       - retro_game_info_ext::dir is guaranteed to contain a
+    *         valid path to the directory in which the compressed file
+    *         (containing the content file) exists
+    *       - retro_game_info_ext::name is guaranteed to contain
+    *         EITHER
+    *         1) the basename of the compressed file (containing
+    *            the content file), without extension
+    *         OR
+    *         2) the basename of the content file inside the
+    *            compressed file, without extension
+    *         In either case, a core should consider 'name' to
+    *         be the canonical name/ID of the the content file
+    *       - retro_game_info_ext::ext is guaranteed to contain the
+    *         extension of the content file inside the compressed file,
+    *         in lower case format
+    *    - retro_game_info_ext::data and retro_game_info_ext::size are
+    *      guaranteed to be valid */
+   bool need_fullpath;
+
+   /* If need_fullpath is false, specifies whether the content
+    * data buffer available in retro_load_game() is 'persistent'
+    *
+    * If persistent_data is false and retro_load_game() is called:
+    *    - retro_game_info::data and retro_game_info::size
+    *      are valid only until retro_load_game() returns
+    *    - retro_game_info_ext::data and retro_game_info_ext::size
+    *      are valid only until retro_load_game() returns
+    *
+    * If persistent_data is true and retro_load_game() is called:
+    *    - retro_game_info::data and retro_game_info::size
+    *      are valid until retro_deinit() returns
+    *    - retro_game_info_ext::data and retro_game_info_ext::size
+    *      are valid until retro_deinit() returns */
+   bool persistent_data;
+};
+
+/* Similar to retro_game_info, but provides extended
+ * information about the source content file and
+ * game memory buffer status.
+ * And array of retro_game_info_ext is returned by
+ * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT
+ * NOTE: In the following descriptions, references to
+ *       retro_load_game() may be replaced with
+ *       retro_load_game_special() */
+struct retro_game_info_ext
+{
+   /* - If file_in_archive is false, contains a valid
+    *   path to an existent content file (UTF-8 encoded)
+    * - If file_in_archive is true, may be NULL */
+   const char *full_path;
+
+   /* - If file_in_archive is false, may be NULL
+    * - If file_in_archive is true, contains a valid path
+    *   to an existent compressed file inside which the
+    *   content file is located (UTF-8 encoded) */
+   const char *archive_path;
+
+   /* - If file_in_archive is false, may be NULL
+    * - If file_in_archive is true, contain a valid path
+    *   to an existent content file inside the compressed
+    *   file referred to by archive_path (UTF-8 encoded)
+    *      e.g. for a compressed file '/path/to/foo.zip'
+    *      containing 'bar.sfc'
+    *      > archive_path will be '/path/to/foo.zip'
+    *      > archive_file will be 'bar.sfc' */
+   const char *archive_file;
+
+   /* - If file_in_archive is false, contains a valid path
+    *   to the directory in which the content file exists
+    *   (UTF-8 encoded)
+    * - If file_in_archive is true, contains a valid path
+    *   to the directory in which the compressed file
+    *   (containing the content file) exists (UTF-8 encoded) */
+   const char *dir;
+
+   /* Contains the canonical name/ID of the content file
+    * (UTF-8 encoded). Intended for use when identifying
+    * 'complementary' content named after the loaded file -
+    * i.e. companion data of a different format (a CD image
+    * required by a ROM), texture packs, internally handled
+    * save files, etc.
+    * - If file_in_archive is false, contains the basename
+    *   of the content file, without extension
+    * - If file_in_archive is true, then string is
+    *   implementation specific. A frontend may choose to
+    *   set a name value of:
+    *   EITHER
+    *   1) the basename of the compressed file (containing
+    *      the content file), without extension
+    *   OR
+    *   2) the basename of the content file inside the
+    *      compressed file, without extension
+    *   RetroArch sets the 'name' value according to (1).
+    *   A frontend that supports routine loading of
+    *   content from archives containing multiple unrelated
+    *   content files may set the 'name' value according
+    *   to (2). */
+   const char *name;
+
+   /* - If file_in_archive is false, contains the extension
+    *   of the content file in lower case format
+    * - If file_in_archive is true, contains the extension
+    *   of the content file inside the compressed file,
+    *   in lower case format */
+   const char *ext;
+
+   /* String of implementation specific meta-data. */
+   const char *meta;
+
+   /* Memory buffer of loaded game content. Will be NULL:
+    * IF
+    * - retro_system_info::need_fullpath is true and
+    *   retro_system_content_info_override::need_fullpath
+    *   is unset
+    * OR
+    * - retro_system_content_info_override::need_fullpath
+    *   is true */
+   const void *data;
+
+   /* Size of game content memory buffer, in bytes */
+   size_t size;
+
+   /* True if loaded content file is inside a compressed
+    * archive */
+   bool file_in_archive;
+
+   /* - If data is NULL, value is unset/ignored
+    * - If data is non-NULL:
+    *   - If persistent_data is false, data and size are
+    *     valid only until retro_load_game() returns
+    *   - If persistent_data is true, data and size are
+    *     are valid until retro_deinit() returns */
+   bool persistent_data;
+};
+
+struct retro_game_geometry
+{
+   unsigned base_width;    /* Nominal video width of game. */
+   unsigned base_height;   /* Nominal video height of game. */
+   unsigned max_width;     /* Maximum possible width of game. */
+   unsigned max_height;    /* Maximum possible height of game. */
+
+   float    aspect_ratio;  /* Nominal aspect ratio of game. If
+                            * aspect_ratio is <= 0.0, an aspect ratio
+                            * of base_width / base_height is assumed.
+                            * A frontend could override this setting,
+                            * if desired. */
+};
+
+struct retro_system_timing
+{
+   double fps;             /* FPS of video content. */
+   double sample_rate;     /* Sampling rate of audio. */
+};
+
+struct retro_system_av_info
+{
+   struct retro_game_geometry geometry;
+   struct retro_system_timing timing;
+};
+
+struct retro_variable
+{
+   /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
+    * If NULL, obtains the complete environment string if more
+    * complex parsing is necessary.
+    * The environment string is formatted as key-value pairs
+    * delimited by semicolons as so:
+    * "key1=value1;key2=value2;..."
+    */
+   const char *key;
+
+   /* Value to be obtained. If key does not exist, it is set to NULL. */
+   const char *value;
+};
+
+struct retro_core_option_display
+{
+   /* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */
+   const char *key;
+
+   /* Specifies whether variable should be displayed
+    * when presenting core options to the user */
+   bool visible;
+};
+
+/* Maximum number of values permitted for a core option
+ * > Note: We have to set a maximum value due the limitations
+ *   of the C language - i.e. it is not possible to create an
+ *   array of structs each containing a variable sized array,
+ *   so the retro_core_option_definition values array must
+ *   have a fixed size. The size limit of 128 is a balancing
+ *   act - it needs to be large enough to support all 'sane'
+ *   core options, but setting it too large may impact low memory
+ *   platforms. In practise, if a core option has more than
+ *   128 values then the implementation is likely flawed.
+ *   To quote the above API reference:
+ *      "The number of possible options should be very limited
+ *       i.e. it should be feasible to cycle through options
+ *       without a keyboard."
+ */
+#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128
+
+struct retro_core_option_value
+{
+   /* Expected option value */
+   const char *value;
+
+   /* Human-readable value label. If NULL, value itself
+    * will be displayed by the frontend */
+   const char *label;
+};
+
+struct retro_core_option_definition
+{
+   /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */
+   const char *key;
+
+   /* Human-readable core option description (used as menu label) */
+   const char *desc;
+
+   /* Human-readable core option information (used as menu sublabel) */
+   const char *info;
+
+   /* Array of retro_core_option_value structs, terminated by NULL */
+   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];
+
+   /* Default core option value. Must match one of the values
+    * in the retro_core_option_value array, otherwise will be
+    * ignored */
+   const char *default_value;
+};
+
+#ifdef __PS3__
+#undef local
+#endif
+
+struct retro_core_options_intl
+{
+   /* Pointer to an array of retro_core_option_definition structs
+    * - US English implementation
+    * - Must point to a valid array */
+   struct retro_core_option_definition *us;
+
+   /* Pointer to an array of retro_core_option_definition structs
+    * - Implementation for current frontend language
+    * - May be NULL */
+   struct retro_core_option_definition *local;
+};
+
+struct retro_core_option_v2_category
+{
+   /* Variable uniquely identifying the
+    * option category. Valid key characters
+    * are [a-z, A-Z, 0-9, _, -] */
+   const char *key;
+
+   /* Human-readable category description
+    * > Used as category menu label when
+    *   frontend has core option category
+    *   support */
+   const char *desc;
+
+   /* Human-readable category information
+    * > Used as category menu sublabel when
+    *   frontend has core option category
+    *   support
+    * > Optional (may be NULL or an empty
+    *   string) */
+   const char *info;
+};
+
+struct retro_core_option_v2_definition
+{
+   /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
+    * Valid key characters are [a-z, A-Z, 0-9, _, -] */
+   const char *key;
+
+   /* Human-readable core option description
+    * > Used as menu label when frontend does
+    *   not have core option category support
+    *   e.g. "Video > Aspect Ratio" */
+   const char *desc;
+
+   /* Human-readable core option description
+    * > Used as menu label when frontend has
+    *   core option category support
+    *   e.g. "Aspect Ratio", where associated
+    *   retro_core_option_v2_category::desc
+    *   is "Video"
+    * > If empty or NULL, the string specified by
+    *   desc will be used as the menu label
+    * > Will be ignored (and may be set to NULL)
+    *   if category_key is empty or NULL */
+   const char *desc_categorized;
+
+   /* Human-readable core option information
+    * > Used as menu sublabel */
+   const char *info;
+
+   /* Human-readable core option information
+    * > Used as menu sublabel when frontend
+    *   has core option category support
+    *   (e.g. may be required when info text
+    *   references an option by name/desc,
+    *   and the desc/desc_categorized text
+    *   for that option differ)
+    * > If empty or NULL, the string specified by
+    *   info will be used as the menu sublabel
+    * > Will be ignored (and may be set to NULL)
+    *   if category_key is empty or NULL */
+   const char *info_categorized;
+
+   /* Variable specifying category (e.g. "video",
+    * "audio") that will be assigned to the option
+    * if frontend has core option category support.
+    * > Categorized options will be displayed in a
+    *   subsection/submenu of the frontend core
+    *   option interface
+    * > Specified string must match one of the
+    *   retro_core_option_v2_category::key values
+    *   in the associated retro_core_option_v2_category
+    *   array; If no match is not found, specified
+    *   string will be considered as NULL
+    * > If specified string is empty or NULL, option will
+    *   have no category and will be shown at the top
+    *   level of the frontend core option interface */
+   const char *category_key;
+
+   /* Array of retro_core_option_value structs, terminated by NULL */
+   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];
+
+   /* Default core option value. Must match one of the values
+    * in the retro_core_option_value array, otherwise will be
+    * ignored */
+   const char *default_value;
+};
+
+struct retro_core_options_v2
+{
+   /* Array of retro_core_option_v2_category structs,
+    * terminated by NULL
+    * > If NULL, all entries in definitions array
+    *   will have no category and will be shown at
+    *   the top level of the frontend core option
+    *   interface
+    * > Will be ignored if frontend does not have
+    *   core option category support */
+   struct retro_core_option_v2_category *categories;
+
+   /* Array of retro_core_option_v2_definition structs,
+    * terminated by NULL */
+   struct retro_core_option_v2_definition *definitions;
+};
+
+struct retro_core_options_v2_intl
+{
+   /* Pointer to a retro_core_options_v2 struct
+    * > US English implementation
+    * > Must point to a valid struct */
+   struct retro_core_options_v2 *us;
+
+   /* Pointer to a retro_core_options_v2 struct
+    * - Implementation for current frontend language
+    * - May be NULL */
+   struct retro_core_options_v2 *local;
+};
+
+/* Used by the frontend to monitor changes in core option
+ * visibility. May be called each time any core option
+ * value is set via the frontend.
+ * - On each invocation, the core must update the visibility
+ *   of any dynamically hidden options using the
+ *   RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY environment
+ *   callback.
+ * - On the first invocation, returns 'true' if the visibility
+ *   of any core option has changed since the last call of
+ *   retro_load_game() or retro_load_game_special().
+ * - On each subsequent invocation, returns 'true' if the
+ *   visibility of any core option has changed since the last
+ *   time the function was called. */
+typedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void);
+struct retro_core_options_update_display_callback
+{
+   retro_core_options_update_display_callback_t callback;
+};
+
+struct retro_game_info
+{
+   const char *path;       /* Path to game, UTF-8 encoded.
+                            * Sometimes used as a reference for building other paths.
+                            * May be NULL if game was loaded from stdin or similar,
+                            * but in this case some cores will be unable to load `data`.
+                            * So, it is preferable to fabricate something here instead
+                            * of passing NULL, which will help more cores to succeed.
+                            * retro_system_info::need_fullpath requires
+                            * that this path is valid. */
+   const void *data;       /* Memory buffer of loaded game. Will be NULL
+                            * if need_fullpath was set. */
+   size_t      size;       /* Size of memory buffer. */
+   const char *meta;       /* String of implementation specific meta-data. */
+};
+
+#define RETRO_MEMORY_ACCESS_WRITE (1 << 0)
+   /* The core will write to the buffer provided by retro_framebuffer::data. */
+#define RETRO_MEMORY_ACCESS_READ (1 << 1)
+   /* The core will read from retro_framebuffer::data. */
+#define RETRO_MEMORY_TYPE_CACHED (1 << 0)
+   /* The memory in data is cached.
+    * If not cached, random writes and/or reading from the buffer is expected to be very slow. */
+struct retro_framebuffer
+{
+   void *data;                      /* The framebuffer which the core can render into.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER.
+                                       The initial contents of data are unspecified. */
+   unsigned width;                  /* The framebuffer width used by the core. Set by core. */
+   unsigned height;                 /* The framebuffer height used by the core. Set by core. */
+   size_t pitch;                    /* The number of bytes between the beginning of a scanline,
+                                       and beginning of the next scanline.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+   enum retro_pixel_format format;  /* The pixel format the core must use to render into data.
+                                       This format could differ from the format used in
+                                       SET_PIXEL_FORMAT.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+
+   unsigned access_flags;           /* How the core will access the memory in the framebuffer.
+                                       RETRO_MEMORY_ACCESS_* flags.
+                                       Set by core. */
+   unsigned memory_flags;           /* Flags telling core how the memory has been mapped.
+                                       RETRO_MEMORY_TYPE_* flags.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+};
+
+/* Used by a libretro core to override the current
+ * fastforwarding mode of the frontend */
+struct retro_fastforwarding_override
+{
+   /* Specifies the runtime speed multiplier that
+    * will be applied when 'fastforward' is true.
+    * For example, a value of 5.0 when running 60 FPS
+    * content will cap the fast-forward rate at 300 FPS.
+    * Note that the target multiplier may not be achieved
+    * if the host hardware has insufficient processing
+    * power.
+    * Setting a value of 0.0 (or greater than 0.0 but
+    * less than 1.0) will result in an uncapped
+    * fast-forward rate (limited only by hardware
+    * capacity).
+    * If the value is negative, it will be ignored
+    * (i.e. the frontend will use a runtime speed
+    * multiplier of its own choosing) */
+   float ratio;
+
+   /* If true, fastforwarding mode will be enabled.
+    * If false, fastforwarding mode will be disabled. */
+   bool fastforward;
+
+   /* If true, and if supported by the frontend, an
+    * on-screen notification will be displayed while
+    * 'fastforward' is true.
+    * If false, and if supported by the frontend, any
+    * on-screen fast-forward notifications will be
+    * suppressed */
+   bool notification;
+
+   /* If true, the core will have sole control over
+    * when fastforwarding mode is enabled/disabled;
+    * the frontend will not be able to change the
+    * state set by 'fastforward' until either
+    * 'inhibit_toggle' is set to false, or the core
+    * is unloaded */
+   bool inhibit_toggle;
+};
+
+/* During normal operation. Rate will be equal to the core's internal FPS. */
+#define RETRO_THROTTLE_NONE              0
+
+/* While paused or stepping single frames. Rate will be 0. */
+#define RETRO_THROTTLE_FRAME_STEPPING    1
+
+/* During fast forwarding.
+ * Rate will be 0 if not specifically limited to a maximum speed. */
+#define RETRO_THROTTLE_FAST_FORWARD      2
+
+/* During slow motion. Rate will be less than the core's internal FPS. */
+#define RETRO_THROTTLE_SLOW_MOTION       3
+
+/* While rewinding recorded save states. Rate can vary depending on the rewind
+ * speed or be 0 if the frontend is not aiming for a specific rate. */
+#define RETRO_THROTTLE_REWINDING         4
+
+/* While vsync is active in the video driver and the target refresh rate is
+ * lower than the core's internal FPS. Rate is the target refresh rate. */
+#define RETRO_THROTTLE_VSYNC             5
+
+/* When the frontend does not throttle in any way. Rate will be 0.
+ * An example could be if no vsync or audio output is active. */
+#define RETRO_THROTTLE_UNBLOCKED         6
+
+struct retro_throttle_state
+{
+   /* The current throttling mode. Should be one of the values above. */
+   unsigned mode;
+
+   /* How many times per second the frontend aims to call retro_run.
+    * Depending on the mode, it can be 0 if there is no known fixed rate.
+    * This won't be accurate if the total processing time of the core and
+    * the frontend is longer than what is available for one frame. */
+   float rate;
+};
+
+/**
+ * Opaque handle to a microphone that's been opened for use.
+ * The underlying object is accessed or created with \c retro_microphone_interface_t.
+ */
+typedef struct retro_microphone retro_microphone_t;
+
+/**
+ * Parameters for configuring a microphone.
+ * Some of these might not be honored,
+ * depending on the available hardware and driver configuration.
+ */
+typedef struct retro_microphone_params
+{
+   /**
+    * The desired sample rate of the microphone's input, in Hz.
+    * The microphone's input will be resampled,
+    * so cores can ask for whichever frequency they need.
+    *
+    * If zero, some reasonable default will be provided by the frontend
+    * (usually from its config file).
+    *
+    * @see retro_get_mic_rate_t
+    */
+   unsigned rate;
+} retro_microphone_params_t;
+
+/**
+ * @copydoc retro_microphone_interface::open_mic
+ */
+typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);
+
+/**
+ * @copydoc retro_microphone_interface::close_mic
+ */
+typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);
+
+/**
+ * @copydoc retro_microphone_interface::get_params
+ */
+typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);
+
+/**
+ * @copydoc retro_microphone_interface::set_mic_state
+ */
+typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);
+
+/**
+ * @copydoc retro_microphone_interface::get_mic_state
+ */
+typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);
+
+/**
+ * @copydoc retro_microphone_interface::read_mic
+ */
+typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);
+
+/**
+ * The current version of the microphone interface.
+ * Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t
+ * receive new fields.
+ *
+ * Frontends using cores built against older mic interface versions
+ * should not access fields introduced in newer versions.
+ */
+#define RETRO_MICROPHONE_INTERFACE_VERSION 1
+
+/**
+ * An interface for querying the microphone and accessing data read from it.
+ *
+ * @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE
+ */
+struct retro_microphone_interface
+{
+   /**
+    * The version of this microphone interface.
+    * Set by the core to request a particular version,
+    * and set by the frontend to indicate the returned version.
+    * 0 indicates that the interface is invalid or uninitialized.
+    */
+   unsigned interface_version;
+
+   /**
+    * Initializes a new microphone.
+    * Assuming that microphone support is enabled and provided by the frontend,
+    * cores may call this function whenever necessary.
+    * A microphone could be opened throughout a core's lifetime,
+    * or it could wait until a microphone is plugged in to the emulated device.
+    *
+    * The returned handle will be valid until it's freed,
+    * even if the audio driver is reinitialized.
+    *
+    * This function is not guaranteed to be thread-safe.
+    *
+    * @param args[in] Parameters used to create the microphone.
+    * May be \c NULL, in which case the default value of each parameter will be used.
+    *
+    * @returns Pointer to the newly-opened microphone,
+    * or \c NULL if one couldn't be opened.
+    * This likely means that no microphone is plugged in and recognized,
+    * or the maximum number of supported microphones has been reached.
+    *
+    * @note Microphones are \em inactive by default;
+    * to begin capturing audio, call \c set_mic_state.
+    * @see retro_microphone_params_t
+    */
+   retro_open_mic_t open_mic;
+
+   /**
+    * Closes a microphone that was initialized with \c open_mic.
+    * Calling this function will stop all microphone activity
+    * and free up the resources that it allocated.
+    * Afterwards, the handle is invalid and must not be used.
+    *
+    * A frontend may close opened microphones when unloading content,
+    * but this behavior is not guaranteed.
+    * Cores should close their microphones when exiting, just to be safe.
+    *
+    * @param microphone Pointer to the microphone that was allocated by \c open_mic.
+    * If \c NULL, this function does nothing.
+    *
+    * @note The handle might be reused if another microphone is opened later.
+    */
+   retro_close_mic_t close_mic;
+
+   /**
+    * Returns the configured parameters of this microphone.
+    * These may differ from what was requested depending on
+    * the driver and device configuration.
+    *
+    * Cores should check these values before they start fetching samples.
+    *
+    * Will not change after the mic was opened.
+    *
+    * @param microphone[in] Opaque handle to the microphone
+    * whose parameters will be retrieved.
+    * @param params[out] The parameters object that the
+    * microphone's parameters will be copied to.
+    *
+    * @return \c true if the parameters were retrieved,
+    * \c false if there was an error.
+    */
+   retro_get_mic_params_t get_params;
+
+   /**
+    * Enables or disables the given microphone.
+    * Microphones are disabled by default
+    * and must be explicitly enabled before they can be used.
+    * Disabled microphones will not process incoming audio samples,
+    * and will therefore have minimal impact on overall performance.
+    * Cores may enable microphones throughout their lifetime,
+    * or only for periods where they're needed.
+    *
+    * Cores that accept microphone input should be able to operate without it;
+    * we suggest substituting silence in this case.
+    *
+    * @param microphone Opaque handle to the microphone
+    * whose state will be adjusted.
+    * This will have been provided by \c open_mic.
+    * @param state \c true if the microphone should receive audio input,
+    * \c false if it should be idle.
+    * @returns \c true if the microphone's state was successfully set,
+    * \c false if \c microphone is invalid
+    * or if there was an error.
+    */
+   retro_set_mic_state_t set_mic_state;
+
+   /**
+    * Queries the active state of a microphone at the given index.
+    * Will return whether the microphone is enabled,
+    * even if the driver is paused.
+    *
+    * @param microphone Opaque handle to the microphone
+    * whose state will be queried.
+    * @return \c true if the provided \c microphone is valid and active,
+    * \c false if not or if there was an error.
+    */
+   retro_get_mic_state_t get_mic_state;
+
+   /**
+    * Retrieves the input processed by the microphone since the last call.
+    * \em Must be called every frame unless \c microphone is disabled,
+    * similar to how \c retro_audio_sample_batch_t works.
+    *
+    * @param[in] microphone Opaque handle to the microphone
+    * whose recent input will be retrieved.
+    * @param[out] samples The buffer that will be used to store the microphone's data.
+    * Microphone input is in mono (i.e. one number per sample).
+    * Should be large enough to accommodate the expected number of samples per frame;
+    * for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.
+    * @param[in] num_samples The size of the data buffer in samples (\em not bytes).
+    * Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here.
+    *
+    * @return The number of samples that were copied into \c samples.
+    * If \c microphone is pending driver initialization,
+    * this function will copy silence of the requested length into \c samples.
+    *
+    * Will return -1 if the microphone is disabled,
+    * the audio driver is paused,
+    * or there was an error.
+    */
+   retro_read_mic_t read_mic;
+};
+
+/* Callbacks */
+
+/* Environment callback. Gives implementations a way of performing
+ * uncommon tasks. Extensible. */
+typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);
+
+/* Render a frame. Pixel format is 15-bit 0RGB1555 native endian
+ * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
+ *
+ * Width and height specify dimensions of buffer.
+ * Pitch specifices length in bytes between two lines in buffer.
+ *
+ * For performance reasons, it is highly recommended to have a frame
+ * that is packed in memory, i.e. pitch == width * byte_per_pixel.
+ * Certain graphic APIs, such as OpenGL ES, do not like textures
+ * that are not packed in memory.
+ */
+typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,
+      unsigned height, size_t pitch);
+
+/* Renders a single audio frame. Should only be used if implementation
+ * generates a single sample at a time.
+ * Format is signed 16-bit native endian.
+ */
+typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);
+
+/* Renders multiple audio frames in one go.
+ *
+ * One frame is defined as a sample of left and right channels, interleaved.
+ * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
+ * Only one of the audio callbacks must ever be used.
+ */
+typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,
+      size_t frames);
+
+/* Polls input. */
+typedef void (RETRO_CALLCONV *retro_input_poll_t)(void);
+
+/* Queries for input for player 'port'. device will be masked with
+ * RETRO_DEVICE_MASK.
+ *
+ * Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that
+ * have been set with retro_set_controller_port_device()
+ * will still use the higher level RETRO_DEVICE_JOYPAD to request input.
+ */
+typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,
+      unsigned index, unsigned id);
+
+/* Sets callbacks. retro_set_environment() is guaranteed to be called
+ * before retro_init().
+ *
+ * The rest of the set_* functions are guaranteed to have been called
+ * before the first call to retro_run() is made. */
+RETRO_API void retro_set_environment(retro_environment_t);
+RETRO_API void retro_set_video_refresh(retro_video_refresh_t);
+RETRO_API void retro_set_audio_sample(retro_audio_sample_t);
+RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
+RETRO_API void retro_set_input_poll(retro_input_poll_t);
+RETRO_API void retro_set_input_state(retro_input_state_t);
+
+/* Library global initialization/deinitialization. */
+RETRO_API void retro_init(void);
+RETRO_API void retro_deinit(void);
+
+/* Must return RETRO_API_VERSION. Used to validate ABI compatibility
+ * when the API is revised. */
+RETRO_API unsigned retro_api_version(void);
+
+/* Gets statically known system info. Pointers provided in *info
+ * must be statically allocated.
+ * Can be called at any time, even before retro_init(). */
+RETRO_API void retro_get_system_info(struct retro_system_info *info);
+
+/* Gets information about system audio/video timings and geometry.
+ * Can be called only after retro_load_game() has successfully completed.
+ * NOTE: The implementation of this function might not initialize every
+ * variable if needed.
+ * E.g. geom.aspect_ratio might not be initialized if core doesn't
+ * desire a particular aspect ratio. */
+RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);
+
+/* Sets device to be used for player 'port'.
+ * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all
+ * available ports.
+ * Setting a particular device type is not a guarantee that libretro cores
+ * will only poll input based on that particular device type. It is only a
+ * hint to the libretro core when a core cannot automatically detect the
+ * appropriate input device type on its own. It is also relevant when a
+ * core can change its behavior depending on device type.
+ *
+ * As part of the core's implementation of retro_set_controller_port_device,
+ * the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
+ * frontend if the descriptions for any controls have changed as a
+ * result of changing the device type.
+ */
+RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);
+
+/* Resets the current game. */
+RETRO_API void retro_reset(void);
+
+/* Runs the game for one video frame.
+ * During retro_run(), input_poll callback must be called at least once.
+ *
+ * If a frame is not rendered for reasons where a game "dropped" a frame,
+ * this still counts as a frame, and retro_run() should explicitly dupe
+ * a frame if GET_CAN_DUPE returns true.
+ * In this case, the video callback can take a NULL argument for data.
+ */
+RETRO_API void retro_run(void);
+
+/* Returns the amount of data the implementation requires to serialize
+ * internal state (save states).
+ * Between calls to retro_load_game() and retro_unload_game(), the
+ * returned size is never allowed to be larger than a previous returned
+ * value, to ensure that the frontend can allocate a save state buffer once.
+ */
+RETRO_API size_t retro_serialize_size(void);
+
+/* Serializes internal state. If failed, or size is lower than
+ * retro_serialize_size(), it should return false, true otherwise. */
+RETRO_API bool retro_serialize(void *data, size_t size);
+RETRO_API bool retro_unserialize(const void *data, size_t size);
+
+RETRO_API void retro_cheat_reset(void);
+RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);
+
+/* Loads a game.
+ * Return true to indicate successful loading and false to indicate load failure.
+ */
+RETRO_API bool retro_load_game(const struct retro_game_info *game);
+
+/* Loads a "special" kind of game. Should not be used,
+ * except in extreme cases. */
+RETRO_API bool retro_load_game_special(
+  unsigned game_type,
+  const struct retro_game_info *info, size_t num_info
+);
+
+/* Unloads the currently loaded game. Called before retro_deinit(void). */
+RETRO_API void retro_unload_game(void);
+
+/* Gets region of game. */
+RETRO_API unsigned retro_get_region(void);
+
+/* Gets region of memory. */
+RETRO_API void *retro_get_memory_data(unsigned id);
+RETRO_API size_t retro_get_memory_size(unsigned id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/libretro_d3d.h b/deps/libretro-common/include/libretro_d3d.h
new file mode 100644 (file)
index 0000000..8e18243
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro API header (libretro_d3d.h)
+ * ---------------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_DIRECT3D_H__
+#define LIBRETRO_DIRECT3D_H__
+
+#include "libretro.h"
+
+#ifdef HAVE_D3D11
+
+#include <d3d11.h>
+#include <d3dcompiler.h>
+
+#define RETRO_HW_RENDER_INTERFACE_D3D11_VERSION 1
+
+struct retro_hw_render_interface_d3d11
+{
+  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11. */
+  enum retro_hw_render_interface_type interface_type;
+  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11_VERSION. */
+  unsigned interface_version;
+
+  /* Opaque handle to the d3d11 backend in the frontend
+   * which must be passed along to all function pointers
+   * in this interface.
+   */
+  void* handle;
+  ID3D11Device *device;
+  ID3D11DeviceContext *context;
+  D3D_FEATURE_LEVEL featureLevel;
+  pD3DCompile D3DCompile;
+};
+
+#endif
+
+#ifdef HAVE_D3D12
+
+#include <d3d12.h>
+#include <d3dcompiler.h>
+
+#define RETRO_HW_RENDER_INTERFACE_D3D12_VERSION 1
+
+struct retro_hw_render_interface_d3d12
+{
+  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12. */
+  enum retro_hw_render_interface_type interface_type;
+  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12_VERSION. */
+  unsigned interface_version;
+
+  /* Opaque handle to the d3d12 backend in the frontend
+   * which must be passed along to all function pointers
+   * in this interface.
+   */
+  void* handle;
+  ID3D12Device *device;
+  ID3D12CommandQueue *queue;
+  pD3DCompile D3DCompile;
+  D3D12_RESOURCE_STATES required_state;
+  void (*set_texture)(void* handle, ID3D12Resource* texture, DXGI_FORMAT format);
+};
+
+#endif
+
+#endif /* LIBRETRO_DIRECT3D_H__ */
diff --git a/deps/libretro-common/include/libretro_dspfilter.h b/deps/libretro-common/include/libretro_dspfilter.h
new file mode 100644 (file)
index 0000000..27dd3c7
--- /dev/null
@@ -0,0 +1,187 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro API header (libretro_dspfilter.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_DSPFILTER_API_H__
+#define LIBRETRO_DSPFILTER_API_H__
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#define DSPFILTER_SIMD_SSE      (1 << 0)
+#define DSPFILTER_SIMD_SSE2     (1 << 1)
+#define DSPFILTER_SIMD_VMX      (1 << 2)
+#define DSPFILTER_SIMD_VMX128   (1 << 3)
+#define DSPFILTER_SIMD_AVX      (1 << 4)
+#define DSPFILTER_SIMD_NEON     (1 << 5)
+#define DSPFILTER_SIMD_SSE3     (1 << 6)
+#define DSPFILTER_SIMD_SSSE3    (1 << 7)
+#define DSPFILTER_SIMD_MMX      (1 << 8)
+#define DSPFILTER_SIMD_MMXEXT   (1 << 9)
+#define DSPFILTER_SIMD_SSE4     (1 << 10)
+#define DSPFILTER_SIMD_SSE42    (1 << 11)
+#define DSPFILTER_SIMD_AVX2     (1 << 12)
+#define DSPFILTER_SIMD_VFPU     (1 << 13)
+#define DSPFILTER_SIMD_PS       (1 << 14)
+
+/* A bit-mask of all supported SIMD instruction sets.
+ * Allows an implementation to pick different
+ * dspfilter_implementation structs.
+ */
+typedef unsigned dspfilter_simd_mask_t;
+
+/* Dynamic library endpoint. */
+typedef const struct dspfilter_implementation *(
+      *dspfilter_get_implementation_t)(dspfilter_simd_mask_t mask);
+
+/* The same SIMD mask argument is forwarded to create() callback
+ * as well to avoid having to keep lots of state around. */
+const struct dspfilter_implementation *dspfilter_get_implementation(
+      dspfilter_simd_mask_t mask);
+
+#define DSPFILTER_API_VERSION 1
+
+struct dspfilter_info
+{
+   /* Input sample rate that the DSP plugin receives. */
+   float input_rate;
+};
+
+struct dspfilter_output
+{
+   /* The DSP plugin has to provide the buffering for the
+    * output samples or reuse the input buffer directly.
+    *
+    * The samples are laid out in interleaving order: LRLRLRLR
+    * The range of the samples are [-1.0, 1.0].
+    *
+    * It is not necessary to manually clip values. */
+   float *samples;
+
+   /* Frames which the DSP plugin outputted for the current process.
+    *
+    * One frame is here defined as a combined sample of
+    * left and right channels.
+    *
+    * (I.e. 44.1kHz, 16bit stereo will have
+    * 88.2k samples/sec and 44.1k frames/sec.)
+    */
+   unsigned frames;
+};
+
+struct dspfilter_input
+{
+   /* Input data for the DSP. The samples are interleaved in order: LRLRLRLR
+    *
+    * It is valid for a DSP plug to use this buffer for output as long as
+    * the output size is less or equal to the input.
+    *
+    * This is useful for filters which can output one sample for each
+    * input sample and do not need to maintain its own buffers.
+    *
+    * Block based filters must provide their own buffering scheme.
+    *
+    * The input size is not bound, but it can be safely assumed that it
+    * will not exceed ~100ms worth of audio at a time. */
+   float *samples;
+
+   /* Number of frames for input data.
+    * One frame is here defined as a combined sample of
+    * left and right channels.
+    *
+    * (I.e. 44.1kHz, 16bit stereo will have
+    * 88.2k samples/sec and 44.1k frames/sec.)
+    */
+   unsigned frames;
+};
+
+/* Returns true if config key was found. Otherwise,
+ * returns false, and sets value to default value.
+ */
+typedef int (*dspfilter_config_get_float_t)(void *userdata,
+      const char *key, float *value, float default_value);
+
+typedef int (*dspfilter_config_get_int_t)(void *userdata,
+      const char *key, int *value, int default_value);
+
+/* Allocates an array with values. free() with dspfilter_config_free_t. */
+typedef int (*dspfilter_config_get_float_array_t)(void *userdata,
+      const char *key, float **values, unsigned *out_num_values,
+      const float *default_values, unsigned num_default_values);
+
+typedef int (*dspfilter_config_get_int_array_t)(void *userdata,
+      const char *key, int **values, unsigned *out_num_values,
+      const int *default_values, unsigned num_default_values);
+
+typedef int (*dspfilter_config_get_string_t)(void *userdata,
+      const char *key, char **output, const char *default_output);
+
+/* Calls free() in host runtime. Sometimes needed on Windows.
+ * free() on NULL is fine. */
+typedef void (*dspfilter_config_free_t)(void *ptr);
+
+struct dspfilter_config
+{
+   dspfilter_config_get_float_t get_float;
+   dspfilter_config_get_int_t get_int;
+
+   dspfilter_config_get_float_array_t get_float_array;
+   dspfilter_config_get_int_array_t get_int_array;
+
+   dspfilter_config_get_string_t get_string;
+   /* Avoid problems where DSP plug and host are
+    * linked against different C runtimes. */
+   dspfilter_config_free_t free;
+};
+
+/* Creates a handle of the plugin. Returns NULL if failed. */
+typedef void *(*dspfilter_init_t)(const struct dspfilter_info *info,
+      const struct dspfilter_config *config, void *userdata);
+
+/* Frees the handle. */
+typedef void (*dspfilter_free_t)(void *data);
+
+/* Processes input data.
+ * The plugin is allowed to return variable sizes for output data. */
+typedef void (*dspfilter_process_t)(void *data,
+      struct dspfilter_output *output, const struct dspfilter_input *input);
+
+struct dspfilter_implementation
+{
+   dspfilter_init_t     init;
+   dspfilter_process_t  process;
+   dspfilter_free_t     free;
+
+   /* Must be DSPFILTER_API_VERSION */
+   unsigned api_version;
+
+   /* Human readable identifier of implementation. */
+   const char *ident;
+
+   /* Computer-friendly short version of ident.
+    * Lower case, no spaces and special characters, etc. */
+   const char *short_ident;
+};
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/libretro_gskit_ps2.h b/deps/libretro-common/include/libretro_gskit_ps2.h
new file mode 100644 (file)
index 0000000..033bb1f
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro API header (libretro_d3d.h)
+ * ---------------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_GSKIT_PS2_H_
+#define LIBRETRO_GSKIT_PS2_H_
+
+#include "libretro.h"
+
+#if defined(PS2)
+
+#include <gsKit.h>
+
+#define RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION 2
+
+struct retro_hw_ps2_insets
+{
+  float top;
+  float left;
+  float bottom;
+  float right;
+};
+
+#define empty_ps2_insets (struct retro_hw_ps2_insets){0.f, 0.f, 0.f, 0.f}
+
+struct retro_hw_render_interface_gskit_ps2
+{
+  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2. */
+  enum retro_hw_render_interface_type interface_type;
+  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION. */
+  unsigned interface_version;
+
+  /* Opaque handle to the GSKit_PS2 backend in the frontend
+   * which must be passed along to all function pointers
+   * in this interface.
+   */
+   GSTEXTURE *coreTexture;
+   struct retro_hw_ps2_insets padding;
+};
+typedef struct retro_hw_render_interface_gskit_ps2 RETRO_HW_RENDER_INTEFACE_GSKIT_PS2;
+
+#endif
+
+#endif /* LIBRETRO_GSKIT_PS2_H_ */
diff --git a/deps/libretro-common/include/libretro_vulkan.h b/deps/libretro-common/include/libretro_vulkan.h
new file mode 100644 (file)
index 0000000..bfc93af
--- /dev/null
@@ -0,0 +1,494 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro API header (libretro_vulkan.h)
+ * ---------------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_VULKAN_H__
+#define LIBRETRO_VULKAN_H__
+
+#include <libretro.h>
+#include <vulkan/vulkan.h>
+
+#define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 5
+#define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 2
+
+struct retro_vulkan_image
+{
+   VkImageView image_view;
+   VkImageLayout image_layout;
+   VkImageViewCreateInfo create_info;
+};
+
+typedef void (*retro_vulkan_set_image_t)(void *handle,
+      const struct retro_vulkan_image *image,
+      uint32_t num_semaphores,
+      const VkSemaphore *semaphores,
+      uint32_t src_queue_family);
+
+typedef uint32_t (*retro_vulkan_get_sync_index_t)(void *handle);
+typedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void *handle);
+typedef void (*retro_vulkan_set_command_buffers_t)(void *handle,
+      uint32_t num_cmd,
+      const VkCommandBuffer *cmd);
+typedef void (*retro_vulkan_wait_sync_index_t)(void *handle);
+typedef void (*retro_vulkan_lock_queue_t)(void *handle);
+typedef void (*retro_vulkan_unlock_queue_t)(void *handle);
+typedef void (*retro_vulkan_set_signal_semaphore_t)(void *handle, VkSemaphore semaphore);
+
+typedef const VkApplicationInfo *(*retro_vulkan_get_application_info_t)(void);
+
+struct retro_vulkan_context
+{
+   VkPhysicalDevice gpu;
+   VkDevice device;
+   VkQueue queue;
+   uint32_t queue_family_index;
+   VkQueue presentation_queue;
+   uint32_t presentation_queue_family_index;
+};
+
+/* This is only used in v1 of the negotiation interface.
+ * It is deprecated since it cannot express PDF2 features or optional extensions. */
+typedef bool (*retro_vulkan_create_device_t)(
+      struct retro_vulkan_context *context,
+      VkInstance instance,
+      VkPhysicalDevice gpu,
+      VkSurfaceKHR surface,
+      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
+      const char **required_device_extensions,
+      unsigned num_required_device_extensions,
+      const char **required_device_layers,
+      unsigned num_required_device_layers,
+      const VkPhysicalDeviceFeatures *required_features);
+
+typedef void (*retro_vulkan_destroy_device_t)(void);
+
+/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
+typedef VkInstance (*retro_vulkan_create_instance_wrapper_t)(
+      void *opaque, const VkInstanceCreateInfo *create_info);
+
+/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
+typedef VkInstance (*retro_vulkan_create_instance_t)(
+      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
+      const VkApplicationInfo *app,
+      retro_vulkan_create_instance_wrapper_t create_instance_wrapper,
+      void *opaque);
+
+/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
+typedef VkDevice (*retro_vulkan_create_device_wrapper_t)(
+      VkPhysicalDevice gpu, void *opaque,
+      const VkDeviceCreateInfo *create_info);
+
+/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */
+typedef bool (*retro_vulkan_create_device2_t)(
+      struct retro_vulkan_context *context,
+      VkInstance instance,
+      VkPhysicalDevice gpu,
+      VkSurfaceKHR surface,
+      PFN_vkGetInstanceProcAddr get_instance_proc_addr,
+      retro_vulkan_create_device_wrapper_t create_device_wrapper,
+      void *opaque);
+
+/* Note on thread safety:
+ * The Vulkan API is heavily designed around multi-threading, and
+ * the libretro interface for it should also be threading friendly.
+ * A core should be able to build command buffers and submit
+ * command buffers to the GPU from any thread.
+ */
+
+struct retro_hw_render_context_negotiation_interface_vulkan
+{
+   /* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN. */
+   enum retro_hw_render_context_negotiation_interface_type interface_type;
+   /* Usually set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION,
+    * but can be lower depending on GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT. */
+   unsigned interface_version;
+
+   /* If non-NULL, returns a VkApplicationInfo struct that the frontend can use instead of
+    * its "default" application info.
+    * VkApplicationInfo::apiVersion also controls the target core Vulkan version for instance level functionality.
+    * Lifetime of the returned pointer must remain until the retro_vulkan_context is initialized.
+    *
+    * NOTE: For optimal compatibility with e.g. Android which is very slow to update its loader,
+    * a core version of 1.1 should be requested. Features beyond that can be requested with extensions.
+    * Vulkan 1.0 is only appropriate for legacy cores, but is still supported.
+    * A frontend is free to bump the instance creation apiVersion as necessary if the frontend requires more advanced core features.
+    *
+    * v2: This function must not be NULL, and must not return NULL.
+    * v1: It was not clearly defined if this function could return NULL.
+    *     Frontends should be defensive and provide a default VkApplicationInfo
+    *     if this function returns NULL or if this function is NULL.
+    */
+   retro_vulkan_get_application_info_t get_application_info;
+
+   /* If non-NULL, the libretro core will choose one or more physical devices,
+    * create one or more logical devices and create one or more queues.
+    * The core must prepare a designated PhysicalDevice, Device, Queue and queue family index
+    * which the frontend will use for its internal operation.
+    *
+    * If gpu is not VK_NULL_HANDLE, the physical device provided to the frontend must be this PhysicalDevice if the call succeeds.
+    * The core is still free to use other physical devices for other purposes that are private to the core.
+    *
+    * The frontend will request certain extensions and layers for a device which is created.
+    * The core must ensure that the queue and queue_family_index support GRAPHICS and COMPUTE.
+    *
+    * If surface is not VK_NULL_HANDLE, the core must consider presentation when creating the queues.
+    * If presentation to "surface" is supported on the queue, presentation_queue must be equal to queue.
+    * If not, a second queue must be provided in presentation_queue and presentation_queue_index.
+    * If surface is not VK_NULL_HANDLE, the instance from frontend will have been created with supported for
+    * VK_KHR_surface extension.
+    *
+    * The core is free to set its own queue priorities.
+    * Device provided to frontend is owned by the frontend, but any additional device resources must be freed by core
+    * in destroy_device callback.
+    *
+    * If this function returns true, a PhysicalDevice, Device and Queues are initialized.
+    * If false, none of the above have been initialized and the frontend will attempt
+    * to fallback to "default" device creation, as if this function was never called.
+    */
+   retro_vulkan_create_device_t create_device;
+
+   /* If non-NULL, this callback is called similar to context_destroy for HW_RENDER_INTERFACE.
+    * However, it will be called even if context_reset was not called.
+    * This can happen if the context never succeeds in being created.
+    * destroy_device will always be called before the VkInstance
+    * of the frontend is destroyed if create_device was called successfully so that the core has a chance of
+    * tearing down its own device resources.
+    *
+    * Only auxillary resources should be freed here, i.e. resources which are not part of retro_vulkan_context.
+    * v2: Auxillary instance resources created during create_instance can also be freed here.
+    */
+   retro_vulkan_destroy_device_t destroy_device;
+
+   /* v2 API: If interface_version is < 2, fields below must be ignored.
+    * If the frontend does not support interface version 2, the v1 entry points will be used instead. */
+
+   /* If non-NULL, this is called to create an instance, otherwise a VkInstance is created by the frontend.
+    * v1 interface bug: The only way to enable instance features is through core versions signalled in VkApplicationInfo.
+    * The frontend may request that certain extensions and layers
+    * are enabled on the VkInstance. Application may add additional features.
+    * If app is non-NULL, apiVersion controls the minimum core version required by the application.
+    * Return a VkInstance or VK_NULL_HANDLE. The VkInstance is owned by the frontend.
+    *
+    * Rather than call vkCreateInstance directly, a core must call the CreateInstance wrapper provided with:
+    * VkInstance instance = create_instance_wrapper(opaque, &create_info);
+    * If the core wishes to create a private instance for whatever reason (relying on shared memory for example),
+    * it may call vkCreateInstance directly. */
+   retro_vulkan_create_instance_t create_instance;
+
+   /* If non-NULL and frontend recognizes negotiation interface >= 2, create_device2 takes precedence over create_device.
+    * Similar to create_device, but is extended to better understand new core versions and PDF2 feature enablement.
+    * Requirements for create_device2 are the same as create_device unless a difference is mentioned.
+    *
+    * v2 consideration:
+    * If the chosen gpu by frontend cannot be supported, a core must return false.
+    *
+    * NOTE: "Cannot be supported" is intentionally vaguely defined.
+    * Refusing to run on an iGPU for a very intensive core with desktop GPU as a minimum spec may be in the gray area.
+    * Not supporting optional features is not a good reason to reject a physical device, however.
+    *
+    * On device creation feature with explicit gpu, a frontend should fall back create_device2 with gpu == VK_NULL_HANDLE and let core
+    * decide on a supported device if possible.
+    *
+    * A core must assume that the explicitly provided GPU is the only guaranteed attempt it has to create a device.
+    * A fallback may not be attempted if there are particular reasons why only a specific physical device can work,
+    * but these situations should be esoteric and rare in nature, e.g. a libretro frontend is implemented with external memory
+    * and only LUID matching would work.
+    * Cores and frontends should ensure "best effort" when negotiating like this and appropriate logging is encouraged.
+    *
+    * v1 note: In the v1 version of create_device, it was never expected that create_device would fail like this,
+    * and frontends are not expected to attempt fall backs.
+    *
+    * Rather than call vkCreateDevice directly, a core must call the CreateDevice wrapper provided with:
+    * VkDevice device = create_device_wrapper(gpu, opaque, &create_info);
+    * If the core wishes to create a private device for whatever reason (relying on shared memory for example),
+    * it may call vkCreateDevice directly.
+    *
+    * This allows the frontend to add additional extensions that it requires as well as adjust the PDF2 pNext as required.
+    * It is also possible adjust the queue create infos in case the frontend desires to allocate some private queues.
+    *
+    * The get_instance_proc_addr provided in create_device2 must be the same as create_instance.
+    *
+    * NOTE: The frontend must not disable features requested by application.
+    * NOTE: The frontend must not add any robustness features as some API behavior may change (VK_EXT_descriptor_buffer comes to mind).
+    * I.e. robustBufferAccess and the like. (nullDescriptor from robustness2 is allowed to be enabled).
+    */
+   retro_vulkan_create_device2_t create_device2;
+};
+
+struct retro_hw_render_interface_vulkan
+{
+   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */
+   enum retro_hw_render_interface_type interface_type;
+   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */
+   unsigned interface_version;
+
+   /* Opaque handle to the Vulkan backend in the frontend
+    * which must be passed along to all function pointers
+    * in this interface.
+    *
+    * The rationale for including a handle here (which libretro v1
+    * doesn't currently do in general) is:
+    *
+    * - Vulkan cores should be able to be freely threaded without lots of fuzz.
+    *   This would break frontends which currently rely on TLS
+    *   to deal with multiple cores loaded at the same time.
+    * - Fixing this in general is TODO for an eventual libretro v2.
+    */
+   void *handle;
+
+   /* The Vulkan instance the context is using. */
+   VkInstance instance;
+   /* The physical device used. */
+   VkPhysicalDevice gpu;
+   /* The logical device used. */
+   VkDevice device;
+
+   /* Allows a core to fetch all its needed symbols without having to link
+    * against the loader itself. */
+   PFN_vkGetDeviceProcAddr get_device_proc_addr;
+   PFN_vkGetInstanceProcAddr get_instance_proc_addr;
+
+   /* The queue the core must use to submit data.
+    * This queue and index must remain constant throughout the lifetime
+    * of the context.
+    *
+    * This queue will be the queue that supports graphics and compute
+    * if the device supports compute.
+    */
+   VkQueue queue;
+   unsigned queue_index;
+
+   /* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID,
+    * set which image to use for this frame.
+    *
+    * If num_semaphores is non-zero, the frontend will wait for the
+    * semaphores provided to be signaled before using the results further
+    * in the pipeline.
+    *
+    * Semaphores provided by a single call to set_image will only be
+    * waited for once (waiting for a semaphore resets it).
+    * E.g. set_image, video_refresh, and then another
+    * video_refresh without set_image,
+    * but same image will only wait for semaphores once.
+    *
+    * For this reason, ownership transfer will only occur if semaphores
+    * are waited on for a particular frame in the frontend.
+    *
+    * Using semaphores is optional for synchronization purposes,
+    * but if not using
+    * semaphores, an image memory barrier in vkCmdPipelineBarrier
+    * should be used in the graphics_queue.
+    * Example:
+    *
+    * vkCmdPipelineBarrier(cmd,
+    *    srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+    *    dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+    *    image_memory_barrier = {
+    *       srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+    *       dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
+    *    });
+    *
+    * The use of pipeline barriers instead of semaphores is encouraged
+    * as it is simpler and more fine-grained. A layout transition
+    * must generally happen anyways which requires a
+    * pipeline barrier.
+    *
+    * The image passed to set_image must have imageUsage flags set to at least
+    * VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT.
+    * The core will naturally want to use flags such as
+    * VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or
+    * VK_IMAGE_USAGE_TRANSFER_DST_BIT depending
+    * on how the final image is created.
+    *
+    * The image must also have been created with MUTABLE_FORMAT bit set if
+    * 8-bit formats are used, so that the frontend can reinterpret sRGB
+    * formats as it sees fit.
+    *
+    * Images passed to set_image should be created with TILING_OPTIMAL.
+    * The image layout should be transitioned to either
+    * VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
+    * The actual image layout used must be set in image_layout.
+    *
+    * The image must be a 2D texture which may or not be layered
+    * and/or mipmapped.
+    *
+    * The image must be suitable for linear sampling.
+    * While the image_view is typically the only field used,
+    * the frontend may want to reinterpret the texture as sRGB vs.
+    * non-sRGB for example so the VkImageViewCreateInfo used to
+    * create the image view must also be passed in.
+    *
+    * The data in the pointer to the image struct will not be copied
+    * as the pNext field in create_info cannot be reliably deep-copied.
+    * The image pointer passed to set_image must be valid until
+    * retro_video_refresh_t has returned.
+    *
+    * If frame duping is used when passing NULL to retro_video_refresh_t,
+    * the frontend is free to either use the latest image passed to
+    * set_image or reuse the older pointer passed to set_image the
+    * frame RETRO_HW_FRAME_BUFFER_VALID was last used.
+    *
+    * Essentially, the lifetime of the pointer passed to
+    * retro_video_refresh_t should be extended if frame duping is used
+    * so that the frontend can reuse the older pointer.
+    *
+    * The image itself however, must not be touched by the core until
+    * wait_sync_index has been completed later. The frontend may perform
+    * layout transitions on the image, so even read-only access is not defined.
+    * The exception to read-only rule is if GENERAL layout is used for the image.
+    * In this case, the frontend is not allowed to perform any layout transitions,
+    * so concurrent reads from core and frontend are allowed.
+    *
+    * If frame duping is used, or if set_command_buffers is used,
+    * the frontend will not wait for any semaphores.
+    *
+    * The src_queue_family is used to specify which queue family
+    * the image is currently owned by. If using multiple queue families
+    * (e.g. async compute), the frontend will need to acquire ownership of the
+    * image before rendering with it and release the image afterwards.
+    *
+    * If src_queue_family is equal to the queue family (queue_index),
+    * no ownership transfer will occur.
+    * Similarly, if src_queue_family is VK_QUEUE_FAMILY_IGNORED,
+    * no ownership transfer will occur.
+    *
+    * The frontend will always release ownership back to src_queue_family.
+    * Waiting for frontend to complete with wait_sync_index() ensures that
+    * the frontend has released ownership back to the application.
+    * Note that in Vulkan, transfering ownership is a two-part process.
+    *
+    * Example frame:
+    *  - core releases ownership from src_queue_index to queue_index with VkImageMemoryBarrier.
+    *  - core calls set_image with src_queue_index.
+    *  - Frontend will acquire the image with src_queue_index -> queue_index as well, completing the ownership transfer.
+    *  - Frontend renders the frame.
+    *  - Frontend releases ownership with queue_index -> src_queue_index.
+    *  - Next time image is used, core must acquire ownership from queue_index ...
+    *
+    * Since the frontend releases ownership, we cannot necessarily dupe the frame because
+    * the core needs to make the roundtrip of ownership transfer.
+    */
+   retro_vulkan_set_image_t set_image;
+
+   /* Get the current sync index for this frame which is obtained in
+    * frontend by calling e.g. vkAcquireNextImageKHR before calling
+    * retro_run().
+    *
+    * This index will correspond to which swapchain buffer is currently
+    * the active one.
+    *
+    * Knowing this index is very useful for maintaining safe asynchronous CPU
+    * and GPU operation without stalling.
+    *
+    * The common pattern for synchronization is to receive fences when
+    * submitting command buffers to Vulkan (vkQueueSubmit) and add this fence
+    * to a list of fences for frame number get_sync_index().
+    *
+    * Next time we receive the same get_sync_index(), we can wait for the
+    * fences from before, which will usually return immediately as the
+    * frontend will generally also avoid letting the GPU run ahead too much.
+    *
+    * After the fence has signaled, we know that the GPU has completed all
+    * GPU work related to work submitted in the frame we last saw get_sync_index().
+    *
+    * This means we can safely reuse or free resources allocated in this frame.
+    *
+    * In theory, even if we wait for the fences correctly, it is not technically
+    * safe to write to the image we earlier passed to the frontend since we're
+    * not waiting for the frontend GPU jobs to complete.
+    *
+    * The frontend will guarantee that the appropriate pipeline barrier
+    * in graphics_queue has been used such that
+    * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot
+    * start until the frontend is done with the image.
+    */
+   retro_vulkan_get_sync_index_t get_sync_index;
+
+   /* Returns a bitmask of how many swapchain images we currently have
+    * in the frontend.
+    *
+    * If bit #N is set in the return value, get_sync_index can return N.
+    * Knowing this value is useful for preallocating per-frame management
+    * structures ahead of time.
+    *
+    * While this value will typically remain constant throughout the
+    * applications lifecycle, it may for example change if the frontend
+    * suddently changes fullscreen state and/or latency.
+    *
+    * If this value ever changes, it is safe to assume that the device
+    * is completely idle and all synchronization objects can be deleted
+    * right away as desired.
+    */
+   retro_vulkan_get_sync_index_mask_t get_sync_index_mask;
+
+   /* Instead of submitting the command buffer to the queue first, the core
+    * can pass along its command buffer to the frontend, and the frontend
+    * will submit the command buffer together with the frontends command buffers.
+    *
+    * This has the advantage that the overhead of vkQueueSubmit can be
+    * amortized into a single call. For this mode, semaphores in set_image
+    * will be ignored, so vkCmdPipelineBarrier must be used to synchronize
+    * the core and frontend.
+    *
+    * The command buffers in set_command_buffers are only executed once,
+    * even if frame duping is used.
+    *
+    * If frame duping is used, set_image should be used for the frames
+    * which should be duped instead.
+    *
+    * Command buffers passed to the frontend with set_command_buffers
+    * must not actually be submitted to the GPU until retro_video_refresh_t
+    * is called.
+    *
+    * The frontend must submit the command buffer before submitting any
+    * other command buffers provided by set_command_buffers. */
+   retro_vulkan_set_command_buffers_t set_command_buffers;
+
+   /* Waits on CPU for device activity for the current sync index to complete.
+    * This is useful since the core will not have a relevant fence to sync with
+    * when the frontend is submitting the command buffers. */
+   retro_vulkan_wait_sync_index_t wait_sync_index;
+
+   /* If the core submits command buffers itself to any of the queues provided
+    * in this interface, the core must lock and unlock the frontend from
+    * racing on the VkQueue.
+    *
+    * Queue submission can happen on any thread.
+    * Even if queue submission happens on the same thread as retro_run(),
+    * the lock/unlock functions must still be called.
+    *
+    * NOTE: Queue submissions are heavy-weight. */
+   retro_vulkan_lock_queue_t lock_queue;
+   retro_vulkan_unlock_queue_t unlock_queue;
+
+   /* Sets a semaphore which is signaled when the image in set_image can safely be reused.
+    * The semaphore is consumed next call to retro_video_refresh_t.
+    * The semaphore will be signalled even for duped frames.
+    * The semaphore will be signalled only once, so set_signal_semaphore should be called every frame.
+    * The semaphore may be VK_NULL_HANDLE, which disables semaphore signalling for next call to retro_video_refresh_t.
+    *
+    * This is mostly useful to support use cases where you're rendering to a single image that
+    * is recycled in a ping-pong fashion with the frontend to save memory (but potentially less throughput).
+    */
+   retro_vulkan_set_signal_semaphore_t set_signal_semaphore;
+};
+
+#endif
diff --git a/deps/libretro-common/include/lists/dir_list.h b/deps/libretro-common/include/lists/dir_list.h
new file mode 100644 (file)
index 0000000..60fef10
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (dir_list.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_DIR_LIST_H
+#define __LIBRETRO_SDK_DIR_LIST_H
+
+#include <retro_common_api.h>
+#include <boolean.h>
+
+#include <lists/string_list.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * dir_list_append:
+ * @list               : existing list to append to.
+ * @dir                : directory path.
+ * @ext                : allowed extensions of file directory entries to include.
+ * @include_dirs       : include directories as part of the finished directory listing?
+ * @include_hidden     : include hidden files and directories as part of the finished directory listing?
+ * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
+ * @recursive          : list directory contents recursively
+ *
+ * Create a directory listing, appending to an existing list
+ *
+ * @return Returns true on success, otherwise false.
+ **/
+bool dir_list_append(struct string_list *list, const char *dir, const char *ext,
+      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);
+
+/**
+ * dir_list_new:
+ * @dir                : directory path.
+ * @ext                : allowed extensions of file directory entries to include.
+ * @include_dirs       : include directories as part of the finished directory listing?
+ * @include_hidden     : include hidden files and directories as part of the finished directory listing?
+ * @include_compressed : include compressed files, even when not part of ext.
+ * @recursive          : list directory contents recursively
+ *
+ * Create a directory listing.
+ *
+ * @return pointer to a directory listing of type 'struct string_list *' on success,
+ * NULL in case of error. Has to be freed manually.
+ **/
+struct string_list *dir_list_new(const char *dir, const char *ext,
+      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);
+
+/**
+ * dir_list_initialize:
+ *
+ * NOTE: @list must zero initialised before
+ * calling this function, otherwise UB.
+ **/
+bool dir_list_initialize(struct string_list *list,
+      const char *dir,
+      const char *ext, bool include_dirs,
+      bool include_hidden, bool include_compressed,
+      bool recursive);
+
+/**
+ * dir_list_sort:
+ * @list      : pointer to the directory listing.
+ * @dir_first : move the directories in the listing to the top?
+ *
+ * Sorts a directory listing.
+ **/
+void dir_list_sort(struct string_list *list, bool dir_first);
+
+/**
+ * dir_list_free:
+ * @list : pointer to the directory listing
+ *
+ * Frees a directory listing.
+ **/
+void dir_list_free(struct string_list *list);
+
+bool dir_list_deinitialize(struct string_list *list);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/lists/file_list.h b/deps/libretro-common/include/lists/file_list.h
new file mode 100644 (file)
index 0000000..3f7ebad
--- /dev/null
@@ -0,0 +1,117 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_list.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FILE_LIST_H__
+#define __LIBRETRO_SDK_FILE_LIST_H__
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <boolean.h>
+
+struct item_file
+{
+   void *userdata;
+   void *actiondata;
+   char *path;
+   char *label;
+   char *alt;
+   size_t directory_ptr;
+   size_t entry_idx;
+   unsigned type;
+};
+
+typedef struct file_list
+{
+   struct item_file *list;
+
+   size_t capacity;
+   size_t size;
+} file_list_t;
+
+void *file_list_get_userdata_at_offset(const file_list_t *list,
+      size_t index);
+
+void *file_list_get_actiondata_at_offset(const file_list_t *list,
+      size_t index);
+
+/**
+ * @brief frees the list
+ *
+ * NOTE: This function will also free() the entries actiondata
+ * and userdata fields if they are non-null. If you store complex
+ * or non-contiguous data there, make sure you free it's fields
+ * before calling this function or you might get a memory leak.
+ *
+ * @param list List to be freed
+ */
+void file_list_free(file_list_t *list);
+
+bool file_list_deinitialize(file_list_t *list);
+
+/**
+ * @brief makes the list big enough to contain at least nitems
+ *
+ * This function will not change the capacity if nitems is smaller
+ * than the current capacity.
+ *
+ * @param list The list to open for input
+ * @param nitems Number of items to reserve space for
+ * @return whether or not the operation succeeded
+ */
+bool file_list_reserve(file_list_t *list, size_t nitems);
+
+bool file_list_append(file_list_t *userdata, const char *path,
+      const char *label, unsigned type, size_t current_directory_ptr,
+      size_t entry_index);
+
+bool file_list_insert(file_list_t *list,
+      const char *path, const char *label,
+      unsigned type, size_t directory_ptr,
+      size_t entry_idx,
+      size_t idx);
+
+void file_list_pop(file_list_t *list, size_t *directory_ptr);
+
+void file_list_clear(file_list_t *list);
+
+void file_list_free_userdata(const file_list_t *list, size_t index);
+
+void file_list_free_actiondata(const file_list_t *list, size_t idx);
+
+void file_list_set_alt_at_offset(file_list_t *list, size_t index,
+      const char *alt);
+
+void file_list_sort_on_alt(file_list_t *list);
+
+void file_list_sort_on_type(file_list_t *list);
+
+bool file_list_search(const file_list_t *list, const char *needle,
+      size_t *index);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/lists/linked_list.h b/deps/libretro-common/include/lists/linked_list.h
new file mode 100644 (file)
index 0000000..fc93ba5
--- /dev/null
@@ -0,0 +1,298 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (linked_list.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_LINKED_LIST_H
+#define __LIBRETRO_SDK_LINKED_LIST_H
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+#include <stddef.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * Represents a linked list. Contains any number of elements.
+ */
+typedef struct linked_list linked_list_t;
+
+/**
+ * Represents an iterator for iterating over a linked list. The iterator can
+ * go through the linked list forwards or backwards.
+ */
+typedef struct linked_list_iterator linked_list_iterator_t;
+
+/**
+ * Creates a new linked list with no elements.
+ *
+ * @return New linked list
+ */
+linked_list_t *linked_list_new(void);
+
+/**
+ * @brief frees the memory used by the linked list
+ * 
+ * Frees all of the memory used by this linked list. The values of all
+ * remaining elements are freed using the "free_value" function. Does
+ * nothing if "list" is NULL.
+ *
+ * @param list linked list to free
+ * @param free_value function to use to free remaining values
+ */
+void linked_list_free(linked_list_t *list, void (*free_value)(void *value));
+
+/**
+ * @brief adds an element to the linked list
+ * 
+ * Add a new element to the end of this linked list. Does nothing if
+ * "list" is NULL.
+ *
+ * @param list list to add the element to
+ * @param value new value to add to the linked list
+ */
+void linked_list_add(linked_list_t *list, void *value);
+
+/**
+ * @brief inserts a value into the linked list
+ *
+ * Inserts a value into the linked list at the specified index. Does
+ * nothing if "list" is NULL.
+ *
+ * @param list list to insert the value into
+ * @param index index where the value should be inserted at (can be equal to list size)
+ * @param value value to insert into the linked list
+ */
+void linked_list_insert(linked_list_t *list, size_t index, void *value);
+
+/**
+ * @brief Get the value in the linked list at the provided index.
+ *
+ * Return the value vstored in the linked list at the provided index. Does
+ * nothing if "list" is NULL.
+ *
+ * @param list list to get the value from
+ * @param index index of the value to return
+ * @return value in the list at the provided index
+ */
+void *linked_list_get(linked_list_t *list, size_t index);
+
+/**
+ * @brief Get the first value that is matched by the provided function
+ *
+ * Return the first value that the function matches. The matches function
+ * parameters are value from the linked list and the provided state.
+ *
+ * @param list list to get the value from
+ * @param matches function to test the values with
+ * @param usrptr user data to pass to the matches function
+ * @return first value that matches otherwise NULL
+ */
+void *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);
+
+/**
+ * @brief Get the last value that is matched by the provided function
+ *
+ * Return the last value that the function matches. The matches function
+ * parameters are value from the linked list and the provided state.
+ *
+ * @param list list to get the value from
+ * @param matches function to test the values with
+ * @param usrptr user data to pass to the matches function
+ * @return last value that matches otherwise NULL
+ */
+void *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);
+
+/**
+ * @brief Remove the element at the provided index
+ *
+ * Removes the element of the linked list at the provided index.
+ *
+ * @param list linked list to remove the element from
+ * @param index index of the element to remove
+ * @return value of the element that was removed, NULL if list is NULL or
+ *         index is invalid
+ */
+void *linked_list_remove_at(linked_list_t *list, size_t index);
+
+/**
+ * @brief Remove the first element with the provided value
+ *
+ * Removes the first element with a value equal to the provided value.
+ * Does nothing if "list" is NULL.
+ *
+ * @param list linked list to remove the element from
+ * @param value value of the element to remove
+ * @return value if a matching element was removed
+ */
+void *linked_list_remove_first(linked_list_t *list, void *value);
+
+/**
+ * @brief Remove the last element with the provided value
+ *
+ * Removes the last element with a value equal to the provided value.
+ * Does nothing if "list" is NULL.
+ *
+ * @param list linked list to remove the element from
+ * @param value value of the element to remove
+ * @return value if a matching element was removed
+ */
+void *linked_list_remove_last(linked_list_t *list, void *value);
+
+/**
+ * @brief Remove all elements with the provided value
+ *
+ * Removes all elements with a value equal to the provided value.
+ * Does nothing if "list" is NULL.
+ *
+ * @param list linked list to remove the elements from
+ * @param value value of the elements to remove
+ * @return value if any matching element(s) where removed
+ */
+void *linked_list_remove_all(linked_list_t *list, void *value);
+
+/**
+ * @brief Remove the first matching element
+ *
+ * Removes the first matching element from the linked list. The "matches" function
+ * is used to test for matching element values. Does nothing if "list" is NULL.
+ *
+ * @param list linked list to remove the element from
+ * @param matches function to use for testing element values for a match
+ * @return value if a matching element was removed
+ */
+void *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value));
+
+/**
+ * @brief Remove the last matching element
+ *
+ * Removes the last matching element from the linked list. The "matches" function
+ * is used to test for matching element values.
+ *
+ * @param list linked list to remove the element from
+ * @param matches function to use for testing element value for a match
+ * @return value if a matching element was removed
+ */
+void *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value));
+
+/**
+ * @brief Remove all matching elements
+ *
+ * Removes all matching elements from the linked list. The "matches" function
+ * is used to test for matching element values. Does nothing if "list" is NULL.
+ *
+ * @param list linked list to remove the elements from
+ * @param matches function to use for testing element values for a match
+ */
+void linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value));
+
+/**
+ * @brief Replace the value of the element at the provided index
+ *
+ * Replaces the value of the element at the provided index. The linked list must
+ * contain an element at the index.
+ *
+ * @param list linked list to replace the value in
+ * @param index index of the element to replace the value of
+ * @param value new value for the selected element
+ * @return whether an element was updated
+ */
+bool linked_list_set_at(linked_list_t *list, size_t index, void *value);
+
+/**
+ * @brief Get the size of the linked list
+ *
+ * Returns the number of elements in the linked list.
+ *
+ * @param linked list to get the size of
+ * @return number of elements in the linked list, 0 if linked list is NULL
+ */
+size_t linked_list_size(linked_list_t *list);
+
+/**
+ * @brief Get an iterator for the linked list
+ *
+ * Returns a new iterator for the linked list. Can be either a forward or backward
+ * iterator.
+ *
+ * @param list linked list to iterate over
+ * @param forward true for a forward iterator, false for backwards
+ * @return new iterator for the linked list in the specified direction, NULL if
+ *         "list" is NULL
+ */
+linked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward);
+
+/**
+ * @brief Move to the next element in the linked list
+ *
+ * Moves the iterator to the next element in the linked list. The direction is
+ * specified when retrieving a new iterator.
+ *
+ * @param iterator iterator for the current element
+ * @return iterator for the next element, NULL if iterator is NULL or "iterator"
+ *         is at the last element
+ */
+linked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator);
+
+/**
+ * @brief Get the value of the element for the iterator
+ *
+ * Returns the value of the element that the iterator is at.
+ *
+ * @param iterator iterator for the current element
+ * @return value of the element for the iterator
+ */
+void *linked_list_iterator_value(linked_list_iterator_t *iterator);
+
+/**
+ * @brief Remove the element that the iterator is at
+ *
+ * Removes the element that the iterator is at. The iterator is updated to the
+ * next element.
+ *
+ * @param iterator iterator for the current element
+ * @return updated iterator or NULL if the last element was removed
+ */
+linked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator);
+
+/**
+ * @brief Release the memory for the iterator
+ *
+ * Frees the memory for the provided iterator. Does nothing if "iterator" is NULL.
+ *
+ * @param iterator iterator to free
+ */
+void linked_list_iterator_free(linked_list_iterator_t *iterator);
+
+/**
+ * @brief Apply the provided function to all values in the linked list
+ *
+ * Apply the provied function to all values in the linked list. The values are applied
+ * in the forward direction. Does nothing if "list" is NULL.
+ *
+ * @param list linked list to apply the function to
+ * @param fn function to apply to all elements
+ */
+void linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value));
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/lists/nested_list.h b/deps/libretro-common/include/lists/nested_list.h
new file mode 100644 (file)
index 0000000..be6ca68
--- /dev/null
@@ -0,0 +1,242 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nested_list.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_NESTED_LIST_H__
+#define __LIBRETRO_SDK_NESTED_LIST_H__
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+RETRO_BEGIN_DECLS
+
+/* Prevent direct access to nested_list_* members */
+typedef struct nested_list_item nested_list_item_t;
+typedef struct nested_list nested_list_t;
+
+/**************************************/
+/* Initialisation / De-Initialisation */
+/**************************************/
+
+/**
+ * nested_list_init:
+ *
+ * Creates a new empty nested list. Returned pointer
+ * must be freed using nested_list_free.
+ *
+ * Returns: Valid nested_list_t pointer if successful,
+ * otherwise NULL.
+ */
+nested_list_t *nested_list_init(void);
+
+/**
+ * nested_list_free:
+ *
+ * @list : pointer to nested_list_t object
+ *
+ * Frees specified nested list.
+ */
+void nested_list_free(nested_list_t *list);
+
+/***********/
+/* Setters */
+/***********/
+
+/**
+ * nested_list_add_item:
+ *
+ * @list    : pointer to nested_list_t object
+ * @address : a delimited list of item identifiers,
+ *            corresponding to item 'levels'
+ * @delim   : delimiter to use when splitting @address
+ *            into individual ids
+ * @value   : optional value (user data) associated with
+ *            new list item. This is added to the last
+ *            item specified by @address
+ *
+ * Appends a new item to the specified nested list.
+ * If @delim is NULL, item is added to the top level
+ * list (@list itself) with id equal to @address.
+ * Otherwise, @address is split by @delim and each
+ * id is added as new 'layer'. For example:
+ *
+ * > @address = "one:two:three", @delim = ":" will
+ *   produce:
+ *      top_level_list:one
+ *                     `- "one" list:two
+ *                                   `- "two" list:three
+ *   where @value is assigned to the "two" list:three
+ *   item.
+ *
+ * Returns: true if successful, otherwise false. Will
+ * always return false if item specified by @address
+ * already exists in the nested list.
+ */
+bool nested_list_add_item(nested_list_t *list,
+      const char *address, const char *delim, const void *value);
+
+/***********/
+/* Getters */
+/***********/
+
+/**
+ * nested_list_get_size:
+ *
+ * @list : pointer to nested_list_t object
+ *
+ * Fetches the current size (number of items) in
+ * the specified list.
+ *
+ * Returns: list size.
+ */
+size_t nested_list_get_size(nested_list_t *list);
+
+/**
+ * nested_list_get_item:
+ *
+ * @list    : pointer to nested_list_t object
+ * @address : a delimited list of item identifiers,
+ *            corresponding to item 'levels'
+ * @delim   : delimiter to use when splitting @address
+ *            into individual ids
+ *
+ * Searches for (and returns) the list item corresponding
+ * to @address. If @delim is NULL, the top level list
+ * (@list itself) is searched for an item with an id
+ * equal to @address. Otherwise, @address is split by
+ * @delim and each id is searched for in a subsequent
+ * list level.
+ *
+ * Returns: valid nested_list_item_t pointer if item
+ * is found, otherwise NULL.
+ */
+nested_list_item_t *nested_list_get_item(nested_list_t *list,
+      const char *address, const char *delim);
+
+/**
+ * nested_list_get_item_idx:
+ *
+ * @list : pointer to nested_list_t object
+ * @idx  : item index
+ *
+ * Fetches the item corresponding to index @idx in
+ * the top level list (@list itself) of the specified
+ * nested list.
+ *
+ * Returns: valid nested_list_item_t pointer if item
+ * exists, otherwise NULL.
+ */
+nested_list_item_t *nested_list_get_item_idx(nested_list_t *list,
+      size_t idx);
+
+/**
+ * nested_list_item_get_parent:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches the parent item of the specified nested
+ * list item. If returned value is NULL, specified
+ * nested list item belongs to a top level list.
+ *
+ * Returns: valid nested_list_item_t pointer if item
+ * has a parent, otherwise NULL.
+ */
+nested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item);
+
+/**
+ * nested_list_item_get_parent_list:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches a pointer to the nested list of which the
+ * specified list item is a direct member.
+ *
+ * Returns: valid nested_list_t pointer if successful,
+ * otherwise NULL.
+ */
+nested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item);
+
+/**
+ * nested_list_item_get_children:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches a pointer to the nested list of child items
+ * belonging to the specified list item.
+ *
+ * Returns: valid nested_list_t pointer if item has
+ * children, otherwise NULL.
+ */
+nested_list_t *nested_list_item_get_children(nested_list_item_t *list_item);
+
+/**
+ * nested_list_item_get_id:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches the id string of the specified list item,
+ * as set by nested_list_add_item().
+ *
+ * Returns: item id if successful, otherwise NULL.
+ */
+const char *nested_list_item_get_id(nested_list_item_t *list_item);
+
+/**
+ * nested_list_item_get_address:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ * @delim     : delimiter to use when concatenating
+ *              individual item ids into a an @address
+ *              string
+ * @address   : a delimited list of item identifiers,
+ *              corresponding to item 'levels'
+ * @len       : length of supplied @address char array
+ * Fetches a compound @address string corresponding to
+ * the specified item's 'position' in the top level
+ * nested list of which it is a member. The resultant
+ * @address may be used to find the item when calling
+ * nested_list_get_item() on the top level nested list.
+ *
+ * Returns: true if successful, otherwise false.
+ */
+bool nested_list_item_get_address(nested_list_item_t *list_item,
+      const char *delim, char *address, size_t len);
+
+/**
+ * nested_list_item_get_value:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches the value (user data) associated with the
+ * specified list item.
+ *
+ * Returns: pointer to user data if set, otherwise
+ * NULL.
+ */
+const void *nested_list_item_get_value(nested_list_item_t *list_item);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/lists/string_list.h b/deps/libretro-common/include/lists/string_list.h
new file mode 100644 (file)
index 0000000..f772193
--- /dev/null
@@ -0,0 +1,205 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (string_list.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_STRING_LIST_H
+#define __LIBRETRO_SDK_STRING_LIST_H
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+RETRO_BEGIN_DECLS
+
+union string_list_elem_attr
+{
+   bool  b;
+   int   i;
+   void *p;
+};
+
+struct string_list_elem
+{
+   char *data;
+   void *userdata;
+   union string_list_elem_attr attr;
+};
+
+struct string_list
+{
+   struct string_list_elem *elems;
+   size_t size;
+   size_t cap;
+};
+
+/**
+ * string_list_find_elem:
+ * @list             : pointer to string list
+ * @elem             : element to find inside the string list.
+ *
+ * Searches for an element (@elem) inside the string list.
+ *
+ * @return Number of elements found, otherwise 0.
+ */
+int string_list_find_elem(const struct string_list *list, const char *elem);
+
+/**
+ * string_list_find_elem_prefix:
+ * @list             : pointer to string list
+ * @prefix           : prefix to append to @elem
+ * @elem             : element to find inside the string list.
+ *
+ * Searches for an element (@elem) inside the string list. Will
+ * also search for the same element prefixed by @prefix.
+ *
+ * Returns: true (1) if element could be found, otherwise false (0).
+ */
+bool string_list_find_elem_prefix(const struct string_list *list,
+      const char *prefix, const char *elem);
+
+/**
+ * string_split:
+ * @str              : string to turn into a string list
+ * @delim            : delimiter character to use for splitting the string.
+ *
+ * Creates a new string list based on string @str, delimited by @delim.
+ *
+ * Returns: new string list if successful, otherwise NULL.
+ */
+struct string_list *string_split(const char *str, const char *delim);
+
+bool string_split_noalloc(struct string_list *list,
+      const char *str, const char *delim);
+
+/**
+ * string_separate:
+ * @str              : string to turn into a string list
+ * @delim            : delimiter character to use for separating the string.
+ *
+ * Creates a new string list based on string @str, delimited by @delim.
+ * Includes empty strings - i.e. two adjacent delimiters will resolve
+ * to a string list element of "".
+ *
+ * @return New string list if successful, otherwise NULL.
+ **/
+struct string_list *string_separate(char *str, const char *delim);
+
+bool string_separate_noalloc(struct string_list *list, 
+      char *str, const char *delim);
+
+bool string_list_deinitialize(struct string_list *list);
+
+bool string_list_initialize(struct string_list *list);
+
+/**
+ * string_list_new:
+ *
+ * Creates a new string list. Has to be freed manually.
+ *
+ * @return New string list if successful, otherwise NULL.
+ **/
+struct string_list *string_list_new(void);
+
+/**
+ * string_list_append:
+ * @list             : pointer to string list
+ * @elem             : element to add to the string list
+ * @attr             : attributes of new element.
+ *
+ * Appends a new element to the string list.
+
+ * Hidden non-leaf function cost:
+ * - Calls string_list_capacity()
+ * - Calls strdup
+ *
+ * @return true if successful, otherwise false.
+ **/
+bool string_list_append(struct string_list *list, const char *elem,
+      union string_list_elem_attr attr);
+
+/**
+ * string_list_append_n:
+ * @list             : pointer to string list
+ * @elem             : element to add to the string list
+ * @length           : read at most this many bytes from elem
+ * @attr             : attributes of new element.
+ *
+ * Appends a new element to the string list.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls string_list_capacity()
+ * - Calls malloc
+ * - Calls strlcpy
+ *
+ * @return true if successful, otherwise false.
+ **/
+bool string_list_append_n(struct string_list *list, const char *elem,
+      unsigned length, union string_list_elem_attr attr);
+
+/**
+ * string_list_free
+ * @list             : pointer to string list object
+ *
+ * Frees a string list.
+ **/
+void string_list_free(struct string_list *list);
+
+/**
+ * string_list_join_concat:
+ * @buffer           : buffer that @list will be joined to.
+ * @size             : length of @buffer.
+ * @list             : pointer to string list.
+ * @delim            : delimiter character for @list.
+ *
+ * A string list will be joined/concatenated as a
+ * string to @buffer, delimited by @delim.
+ *
+ * NOTE: @buffer must be NULL-terminated.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls strlen_size()
+ * - Calls strlcat x times in a loop
+ **/
+void string_list_join_concat(char *buffer, size_t size,
+      const struct string_list *list, const char *sep);
+
+/**
+ * string_list_set:
+ * @list             : pointer to string list
+ * @idx              : index of element in string list
+ * @str              : value for the element.
+ *
+ * Set value of element inside string list.
+ *
+ * Hidden non-leaf function cost:
+ * - Calls free
+ * - Calls strdup
+ **/
+void string_list_set(struct string_list *list, unsigned idx,
+      const char *str);
+
+struct string_list *string_list_clone(const struct string_list *src);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/lrc_hash.h b/deps/libretro-common/include/lrc_hash.h
new file mode 100644 (file)
index 0000000..581c6d7
--- /dev/null
@@ -0,0 +1,95 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (lrc_hash.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_HASH_H
+#define __LIBRETRO_SDK_HASH_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <compat/msvc.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <retro_inline.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * sha256_hash:
+ * @out               : Output.
+ * @in                : Input.
+ * @size              : Size of @out.
+ *
+ * Hashes SHA256 and outputs a human readable string.
+ **/
+void sha256_hash(char *out, const uint8_t *in, size_t size);
+
+int sha1_calculate(const char *path, char *result);
+
+uint32_t djb2_calculate(const char *str);
+
+/* 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;
+
+/*
+ * 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 <solar at openwall.com>
+ *
+ * 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.
+ */
+
+void MD5_Init(MD5_CTX *ctx);
+void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
+void MD5_Final(unsigned char *result, MD5_CTX *ctx);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/math/complex.h b/deps/libretro-common/include/math/complex.h
new file mode 100644 (file)
index 0000000..c7f34d4
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (complex.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_MATH_COMPLEX_H__
+#define __LIBRETRO_SDK_MATH_COMPLEX_H__
+
+#include <stdint.h>
+
+#include <retro_inline.h>
+
+typedef struct
+{
+   float real;
+   float imag;
+} fft_complex_t;
+
+static INLINE fft_complex_t fft_complex_mul(fft_complex_t a,
+      fft_complex_t b)
+{
+   fft_complex_t out;
+   out.real = a.real * b.real - a.imag * b.imag;
+   out.imag = a.imag * b.real + a.real * b.imag;
+
+   return out;
+
+}
+
+static INLINE fft_complex_t fft_complex_add(fft_complex_t a,
+      fft_complex_t b)
+{
+   fft_complex_t out;
+   out.real = a.real + b.real;
+   out.imag = a.imag + b.imag;
+
+   return out;
+
+}
+
+static INLINE fft_complex_t fft_complex_sub(fft_complex_t a,
+      fft_complex_t b)
+{
+   fft_complex_t out;
+   out.real = a.real - b.real;
+   out.imag = a.imag - b.imag;
+
+   return out;
+
+}
+
+static INLINE fft_complex_t fft_complex_conj(fft_complex_t a)
+{
+   fft_complex_t out;
+   out.real = a.real;
+   out.imag = -a.imag;
+
+   return out;
+}
+
+#endif
diff --git a/deps/libretro-common/include/math/float_minmax.h b/deps/libretro-common/include/math/float_minmax.h
new file mode 100644 (file)
index 0000000..bfd2dae
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (float_minmax.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__
+#define __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__
+
+#include <stdint.h>
+#include <math.h>
+
+#include <retro_inline.h>
+#include <retro_miscellaneous.h>
+#include <retro_environment.h>
+
+#ifdef __SSE2__
+#include <emmintrin.h>
+#include <mmintrin.h>
+#endif
+
+static INLINE float float_min(float a, float b)
+{
+#ifdef __SSE2__
+   _mm_store_ss( &a, _mm_min_ss(_mm_set_ss(a),_mm_set_ss(b)) );
+   return a;
+#elif !defined(DJGPP) && (defined(__STDC_C99__) || defined(__STDC_C11__))
+   return fminf(a, b);
+#else
+   return MIN(a, b);
+#endif
+}
+
+static INLINE float float_max(float a, float b)
+{
+#ifdef __SSE2__
+   _mm_store_ss( &a, _mm_max_ss(_mm_set_ss(a),_mm_set_ss(b)) );
+   return a;
+#elif !defined(DJGPP) && (defined(__STDC_C99__) || defined(__STDC_C11__))
+   return fmaxf(a, b);
+#else
+   return MAX(a, b);
+#endif
+}
+
+#endif
diff --git a/deps/libretro-common/include/math/fxp.h b/deps/libretro-common/include/math/fxp.h
new file mode 100644 (file)
index 0000000..895f1dc
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fxp.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_MATH_FXP_H__
+#define __LIBRETRO_SDK_MATH_FXP_H__
+
+#include <stdint.h>
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+#include <retro_inline.h>
+
+static INLINE int64_t fx32_mul(const int32_t a, const int32_t b)
+{
+#ifdef _MSC_VER
+   return __emul(a, b);
+#else
+   return ((int64_t)a) * ((int64_t)b);
+#endif
+}
+
+static INLINE int32_t fx32_shiftdown(const int64_t a)
+{
+#ifdef _MSC_VER
+       return (int32_t)__ll_rshift(a, 12);
+#else
+       return (int32_t)(a >> 12);
+#endif
+}
+
+static INLINE int64_t fx32_shiftup(const int32_t a)
+{
+#ifdef _MSC_VER
+       return __ll_lshift(a, 12);
+#else
+       return ((int64_t)a) << 12;
+#endif
+}
+
+#endif
diff --git a/deps/libretro-common/include/media/media_detect_cd.h b/deps/libretro-common/include/media/media_detect_cd.h
new file mode 100644 (file)
index 0000000..6d8194f
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (media_detect_cd.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_MEDIA_DETECT_CD_H
+#define __LIBRETRO_SDK_MEDIA_DETECT_CD_H
+
+#include <retro_common_api.h>
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+enum media_detect_cd_system
+{
+   MEDIA_CD_SYSTEM_MEGA_CD,
+   MEDIA_CD_SYSTEM_SATURN,
+   MEDIA_CD_SYSTEM_DREAMCAST,
+   MEDIA_CD_SYSTEM_PSX,
+   MEDIA_CD_SYSTEM_3DO,
+   MEDIA_CD_SYSTEM_PC_ENGINE_CD
+};
+
+typedef struct
+{
+   char title[256];
+   char system[128];
+   char region[128];
+   char serial[64];
+   char maker[64];
+   char version[32];
+   char release_date[32];
+   enum media_detect_cd_system system_id;
+} media_detect_cd_info_t;
+
+/* Fill in "info" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */
+bool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info);
+
+/* Fill in "info" with detected CD info. Use this when you have a cue file and want it parsed to find the first data track and any pregap info. */
+bool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/memalign.h b/deps/libretro-common/include/memalign.h
new file mode 100644 (file)
index 0000000..59ffbd7
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (memalign.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_MEMALIGN_H
+#define _LIBRETRO_MEMALIGN_H
+
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+void *memalign_alloc(size_t boundary, size_t size);
+
+void *memalign_alloc_aligned(size_t size);
+
+void memalign_free(void *ptr);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/memmap.h b/deps/libretro-common/include/memmap.h
new file mode 100644 (file)
index 0000000..8897877
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (memmap.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_MEMMAP_H
+#define _LIBRETRO_MEMMAP_H
+
+#include <stdio.h>
+#include <stdint.h>
+
+#if defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX) || defined(__PS3__) || defined(__PSL1GHT__)
+/* No mman available */
+#elif defined(_WIN32) && !defined(_XBOX)
+#include <windows.h>
+#include <errno.h>
+#include <io.h>
+#else
+#define HAVE_MMAN
+#include <sys/mman.h>
+#endif
+
+#if !defined(HAVE_MMAN) || defined(_WIN32)
+void* mmap(void *addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off);
+
+int munmap(void *addr, size_t len);
+
+int mprotect(void *addr, size_t len, int prot);
+#endif
+
+int memsync(void *start, void *end);
+
+int memprotect(void *addr, size_t len);
+
+#endif
diff --git a/deps/libretro-common/include/net/net_compat.h b/deps/libretro-common/include/net/net_compat.h
new file mode 100644 (file)
index 0000000..3408b47
--- /dev/null
@@ -0,0 +1,421 @@
+/* Copyright  (C) 2010-2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_compat.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_NET_COMPAT_H
+#define _LIBRETRO_SDK_NET_COMPAT_H
+
+#include <stdint.h>
+#include <boolean.h>
+#include <retro_inline.h>
+
+#include <errno.h>
+
+#ifndef _WIN32
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#include <retro_common_api.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#define WIN32_LEAN_AND_MEAN
+
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+
+#if _MSC_VER && _MSC_VER <= 1600
+/* If we are using MSVC2010 or lower, disable WSAPoll support 
+ * to ensure Windows XP and earlier backwards compatibility */
+#else
+#ifndef WIN32_SUPPORTS_POLL
+#define WIN32_SUPPORTS_POLL 1
+#endif
+#endif
+
+#if defined(WIN32_SUPPORTS_POLL) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
+#define NETWORK_HAVE_POLL 1
+#endif
+
+#elif defined(_XBOX)
+#define NOD3D
+
+#include <xtl.h>
+#include <io.h>
+
+#ifndef SO_KEEPALIVE
+#define SO_KEEPALIVE 0 /* verify if correct */
+#endif
+
+#define socklen_t unsigned int
+
+#elif defined(VITA)
+#include <psp2/net/net.h>
+#include <psp2/net/netctl.h>
+
+#define NETWORK_HAVE_POLL 1
+
+#define AF_UNSPEC 0
+#define AF_INET SCE_NET_AF_INET
+
+#define SOCK_STREAM SCE_NET_SOCK_STREAM
+#define SOCK_DGRAM SCE_NET_SOCK_DGRAM
+
+#define INADDR_ANY SCE_NET_INADDR_ANY
+#define INADDR_NONE 0xFFFFFFFF
+
+#define SOL_SOCKET SCE_NET_SOL_SOCKET
+#define SO_REUSEADDR SCE_NET_SO_REUSEADDR
+#define SO_KEEPALIVE SCE_NET_SO_KEEPALIVE
+#define SO_BROADCAST SCE_NET_SO_BROADCAST
+#define SO_SNDBUF SCE_NET_SO_SNDBUF
+#define SO_RCVBUF SCE_NET_SO_RCVBUF
+#define SO_SNDTIMEO SCE_NET_SO_SNDTIMEO
+#define SO_RCVTIMEO SCE_NET_SO_RCVTIMEO
+#define SO_ERROR SCE_NET_SO_ERROR
+#define SO_NBIO SCE_NET_SO_NBIO
+
+#define IPPROTO_IP SCE_NET_IPPROTO_IP
+#define IP_MULTICAST_TTL SCE_NET_IP_MULTICAST_TTL
+
+#define IPPROTO_TCP SCE_NET_IPPROTO_TCP
+#define TCP_NODELAY SCE_NET_TCP_NODELAY
+
+#define IPPROTO_UDP SCE_NET_IPPROTO_UDP
+
+#define MSG_DONTWAIT SCE_NET_MSG_DONTWAIT
+
+#define POLLIN   SCE_NET_EPOLLIN
+#define POLLOUT  SCE_NET_EPOLLOUT
+#define POLLERR  SCE_NET_EPOLLERR
+#define POLLHUP  SCE_NET_EPOLLHUP
+#define POLLNVAL 0
+
+#define sockaddr SceNetSockaddr
+#define sockaddr_in SceNetSockaddrIn
+#define in_addr SceNetInAddr
+#define socklen_t unsigned int
+
+#define socket(a,b,c) sceNetSocket("unknown",a,b,c)
+#define getsockname sceNetGetsockname
+#define getsockopt sceNetGetsockopt
+#define setsockopt sceNetSetsockopt
+#define bind sceNetBind
+#define listen sceNetListen
+#define accept sceNetAccept
+#define connect sceNetConnect
+#define send sceNetSend
+#define sendto sceNetSendto
+#define recv sceNetRecv
+#define recvfrom sceNetRecvfrom
+#define htonl sceNetHtonl
+#define ntohl sceNetNtohl
+#define htons sceNetHtons
+#define ntohs sceNetNtohs
+#define inet_ntop sceNetInetNtop
+#define inet_pton sceNetInetPton
+
+#elif defined(GEKKO)
+#include <network.h>
+
+#define NETWORK_HAVE_POLL 1
+
+#define pollfd pollsd
+
+#define socket(a,b,c) net_socket(a,b,c)
+#define getsockopt(a,b,c,d,e) net_getsockopt(a,b,c,d,e)
+#define setsockopt(a,b,c,d,e) net_setsockopt(a,b,c,d,e)
+#define bind(a,b,c) net_bind(a,b,c)
+#define listen(a,b) net_listen(a,b)
+#define accept(a,b,c) net_accept(a,b,c)
+#define connect(a,b,c) net_connect(a,b,c)
+#define send(a,b,c,d) net_send(a,b,c,d)
+#define sendto(a,b,c,d,e,f) net_sendto(a,b,c,d,e,f)
+#define recv(a,b,c,d) net_recv(a,b,c,d)
+#define recvfrom(a,b,c,d,e,f) net_recvfrom(a,b,c,d,e,f)
+#define select(a,b,c,d,e) net_select(a,b,c,d,e)
+#define gethostbyname(a) net_gethostbyname(a)
+
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+
+#include <netinet/in.h>
+#ifndef __PSL1GHT__
+#include <netinet/tcp.h>
+#endif
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+
+#if !defined(__PSL1GHT__) && defined(__PS3__)
+#include <netex/libnetctl.h>
+#include <netex/errno.h>
+#else
+#include <signal.h>
+#endif
+
+#if defined(__PSL1GHT__)
+#include <net/poll.h>
+
+#define NETWORK_HAVE_POLL 1
+
+#elif defined(WIIU)
+#define WIIU_RCVBUF 0x40000
+#define WIIU_SNDBUF 0x40000
+
+#elif !defined(__PS3__)
+#include <poll.h>
+
+#define NETWORK_HAVE_POLL 1
+
+#endif
+#endif
+
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+#if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY) && !defined(_3DS)
+#define HAVE_INET6 1
+#endif
+
+#ifdef NETWORK_HAVE_POLL
+#ifdef GEKKO
+#define NET_POLL_FD(sockfd, sockfds)    (sockfds)->socket  = (sockfd)
+#else
+#define NET_POLL_FD(sockfd, sockfds)    (sockfds)->fd      = (sockfd)
+#endif
+#define NET_POLL_EVENT(sockev, sockfds) (sockfds)->events |= (sockev)
+#define NET_POLL_HAS_EVENT(sockev, sockfds) ((sockfds)->revents & (sockev))
+#endif
+
+RETRO_BEGIN_DECLS
+
+/* Compatibility layer for legacy or incomplete BSD socket implementations.
+ * Only for IPv4. Mostly useful for the consoles which do not support
+ * anything reasonably modern on the socket API side of things. */
+#ifdef HAVE_SOCKET_LEGACY
+#define sockaddr_storage sockaddr_in
+
+#ifdef AI_PASSIVE
+#undef AI_PASSIVE
+#endif
+#ifdef AI_CANONNAME
+#undef AI_CANONNAME
+#endif
+#ifdef AI_NUMERICHOST
+#undef AI_NUMERICHOST
+#endif
+#ifdef AI_NUMERICSERV
+#undef AI_NUMERICSERV
+#endif
+
+#ifdef NI_NUMERICHOST
+#undef NI_NUMERICHOST
+#endif
+#ifdef NI_NUMERICSERV
+#undef NI_NUMERICSERV
+#endif
+#ifdef NI_NOFQDN
+#undef NI_NOFQDN
+#endif
+#ifdef NI_NAMEREQD
+#undef NI_NAMEREQD
+#endif
+#ifdef NI_DGRAM
+#undef NI_DGRAM
+#endif
+
+#define AI_PASSIVE     1
+#define AI_CANONNAME   2
+#define AI_NUMERICHOST 4
+#define AI_NUMERICSERV 8
+
+#define NI_NUMERICHOST 1
+#define NI_NUMERICSERV 2
+#define NI_NOFQDN      4
+#define NI_NAMEREQD    8
+#define NI_DGRAM       16
+
+#ifndef __PS3__
+struct addrinfo
+{
+   int ai_flags;
+   int ai_family;
+   int ai_socktype;
+   int ai_protocol;
+   socklen_t ai_addrlen;
+   struct sockaddr *ai_addr;
+   char *ai_canonname;
+   struct addrinfo *ai_next;
+};
+#endif
+
+/* gai_strerror() not used, so we skip that. */
+
+#else
+/* Ensure that getaddrinfo and getnameinfo flags are always defined. */
+#ifndef AI_PASSIVE
+#define AI_PASSIVE 0
+#endif
+#ifndef AI_CANONNAME
+#define AI_CANONNAME 0
+#endif
+#ifndef AI_NUMERICHOST
+#define AI_NUMERICHOST 0
+#endif
+#ifndef AI_NUMERICSERV
+#define AI_NUMERICSERV 0
+#endif
+
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST 0
+#endif
+#ifndef NI_NUMERICSERV
+#define NI_NUMERICSERV 0
+#endif
+#ifndef NI_NOFQDN
+#define NI_NOFQDN 0
+#endif
+#ifndef NI_NAMEREQD
+#define NI_NAMEREQD 0
+#endif
+#ifndef NI_DGRAM
+#define NI_DGRAM 0
+#endif
+
+#endif
+
+#if defined(_XBOX)
+struct hostent
+{
+   char *h_name;
+   char **h_aliases;
+   int  h_addrtype;
+   int  h_length;
+   char **h_addr_list;
+   char *h_addr;
+   char *h_end;
+};
+
+#elif defined(VITA)
+struct pollfd
+{
+   int fd;
+   unsigned events;
+   unsigned revents;
+   unsigned __pad; /* Align to 64-bits boundary */
+};
+
+struct hostent
+{
+   char *h_name;
+   char **h_aliases;
+   int  h_addrtype;
+   int  h_length;
+   char **h_addr_list;
+   char *h_addr;
+   char *h_end;
+};
+
+#endif
+
+static INLINE bool isagain(int val)
+{
+#if defined(_WIN32)
+   return (val == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK);
+#elif !defined(__PSL1GHT__) && defined(__PS3__)
+   return (sys_net_errno == SYS_NET_EAGAIN) || (sys_net_errno == SYS_NET_EWOULDBLOCK);
+#elif defined(VITA)
+   return (val == SCE_NET_ERROR_EAGAIN) || (val == SCE_NET_ERROR_EWOULDBLOCK);
+#elif defined(WIIU)
+   return (val == -1) && (socketlasterr() == SO_SUCCESS || socketlasterr() == SO_EWOULDBLOCK);
+#else
+   return (val < 0) && (errno == EAGAIN || errno == EWOULDBLOCK);
+#endif
+}
+
+static INLINE bool isinprogress(int val)
+{
+#if defined(_WIN32)
+   return (val == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK);
+#elif !defined(__PSL1GHT__) && defined(__PS3__)
+   return (sys_net_errno == SYS_NET_EINPROGRESS);
+#elif defined(VITA)
+   return (val == SCE_NET_ERROR_EINPROGRESS);
+#elif defined(WIIU)
+   return (val == -1) && (socketlasterr() == SO_EINPROGRESS);
+#else
+   return (val < 0) && (errno == EINPROGRESS);
+#endif
+}
+
+#if defined(_WIN32) && !defined(_XBOX)
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
+int inet_pton(int af, const char *src, void *dst);
+#endif
+
+#elif defined(_XBOX)
+struct hostent *gethostbyname(const char *name);
+
+#elif defined(VITA)
+char *inet_ntoa(struct in_addr in);
+int inet_aton(const char *cp, struct in_addr *inp);
+uint32_t inet_addr(const char *cp);
+
+struct hostent *gethostbyname(const char *name);
+
+#elif defined(GEKKO)
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
+int inet_pton(int af, const char *src, void *dst);
+
+#endif
+
+int getaddrinfo_retro(const char *node, const char *service,
+      struct addrinfo *hints, struct addrinfo **res);
+
+void freeaddrinfo_retro(struct addrinfo *res);
+
+int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
+      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);
+
+bool addr_6to4(struct sockaddr_storage *addr);
+
+bool ipv4_is_lan_address(const struct sockaddr_in *addr);
+bool ipv4_is_cgnat_address(const struct sockaddr_in *addr);
+
+/**
+ * network_init:
+ *
+ * Platform specific socket library initialization.
+ *
+ * @return true if successful, otherwise false.
+ **/
+bool network_init(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/net/net_http.h b/deps/libretro-common/include/net/net_http.h
new file mode 100644 (file)
index 0000000..8523145
--- /dev/null
@@ -0,0 +1,131 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_http.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_NET_HTTP_H
+#define _LIBRETRO_SDK_NET_HTTP_H
+
+#include <stdint.h>
+#include <boolean.h>
+#include <string.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+struct http_t;
+struct http_connection_t;
+
+struct http_connection_t *net_http_connection_new(const char *url, const char *method, const char *data);
+
+/**
+ * net_http_connection_iterate:
+ *
+ * Leaf function.
+ **/
+bool net_http_connection_iterate(struct http_connection_t *conn);
+
+bool net_http_connection_done(struct http_connection_t *conn);
+
+void net_http_connection_free(struct http_connection_t *conn);
+
+void net_http_connection_set_user_agent(struct http_connection_t *conn, const char *user_agent);
+
+void net_http_connection_set_headers(struct http_connection_t *conn, const char *headers);
+
+const char *net_http_connection_url(struct http_connection_t *conn);
+
+const char* net_http_connection_method(struct http_connection_t* conn);
+
+struct http_t *net_http_new(struct http_connection_t *conn);
+
+/**
+ * net_http_fd:
+ *
+ * Leaf function.
+ *
+ * You can use this to call net_http_update
+ * only when something will happen; select() it for reading.
+ **/
+int net_http_fd(struct http_t *state);
+
+/**
+ * net_http_update:
+ *
+ * @return true if it's done, or if something broke.
+ * @total will be 0 if it's not known.
+ **/
+bool net_http_update(struct http_t *state, size_t* progress, size_t* total);
+
+/**
+ * net_http_status:
+ *
+ * Report HTTP status. 200, 404, or whatever.
+ *
+ * Leaf function.
+ * 
+ * @return HTTP status code.
+ **/
+int net_http_status(struct http_t *state);
+
+/**
+ * net_http_error:
+ *
+ * Leaf function
+ **/
+bool net_http_error(struct http_t *state);
+
+/**
+ * net_http_data:
+ *
+ * Leaf function.
+ *
+ * @return the downloaded data. The returned buffer is owned by the
+ * HTTP handler; it's freed by net_http_delete.
+ * If the status is not 20x and accept_error is false, it returns NULL.
+ **/
+uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_error);
+
+/**
+ * net_http_delete:
+ *
+ * Cleans up all memory.
+ **/
+void net_http_delete(struct http_t *state);
+
+/**
+ * net_http_urlencode:
+ *
+ * URL Encode a string
+ * caller is responsible for deleting the destination buffer
+ **/
+void net_http_urlencode(char **dest, const char *source);
+
+/**
+ * net_http_urlencode_full:
+ *
+ * Re-encode a full URL
+ **/
+void net_http_urlencode_full(char *dest, const char *source, size_t size);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/net/net_http_parse.h b/deps/libretro-common/include/net/net_http_parse.h
new file mode 100644 (file)
index 0000000..279e506
--- /dev/null
@@ -0,0 +1,53 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_http.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_NET_HTTP_PARSE_H
+#define _LIBRETRO_SDK_NET_HTTP_PARSE_H
+
+#include <stdint.h>
+#include <boolean.h>
+#include <string.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * string_parse_html_anchor:
+ * @line               : Buffer where the <a> tag is stored
+ * @link               : Buffer to store the link URL in
+ * @name               : Buffer to store the link URL in
+ * @link_size          : Size of the link buffer including the NUL-terminator
+ * @name_size          : Size of the name buffer including the NUL-terminator
+ *
+ * Parses an HTML anchor link stored in @line in the form of: <a href="/path/to/url">Title</a>
+ * The buffer pointed to by @link is filled with the URL path the link points to,
+ * and @name is filled with the title portion of the link.
+ *
+ * @return 0 if URL was parsed completely, otherwise 1.
+ **/
+int string_parse_html_anchor(const char *line, char *link, char *name,
+      size_t link_size, size_t name_size);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/net/net_ifinfo.h b/deps/libretro-common/include/net/net_ifinfo.h
new file mode 100644 (file)
index 0000000..0511b3f
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright  (C) 2010-2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_ifinfo.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_NET_IFINFO_H
+#define _LIBRETRO_SDK_NET_IFINFO_H
+
+#include <stddef.h>
+
+#include <boolean.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+struct net_ifinfo_entry
+{
+   char name[256];
+   char host[256];
+};
+
+typedef struct net_ifinfo
+{
+   struct net_ifinfo_entry *entries;
+   size_t size;
+} net_ifinfo_t;
+
+bool net_ifinfo_new(net_ifinfo_t *list);
+
+void net_ifinfo_free(net_ifinfo_t *list);
+
+bool net_ifinfo_best(const char *dst, void *src, bool ipv6);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/net/net_socket.h b/deps/libretro-common/include/net/net_socket.h
new file mode 100644 (file)
index 0000000..4fa5c13
--- /dev/null
@@ -0,0 +1,118 @@
+/* Copyright  (C) 2010-2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_socket.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_NET_SOCKET_H
+#define _LIBRETRO_SDK_NET_SOCKET_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <boolean.h>
+
+#include <net/net_compat.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+enum socket_domain
+{
+   SOCKET_DOMAIN_INET = 0
+};
+
+enum socket_type
+{
+   SOCKET_TYPE_DATAGRAM = 0,
+   SOCKET_TYPE_STREAM,
+   SOCKET_TYPE_SEQPACKET
+};
+
+enum socket_protocol
+{
+   SOCKET_PROTOCOL_NONE = 0,
+   SOCKET_PROTOCOL_TCP,
+   SOCKET_PROTOCOL_UDP
+};
+
+typedef struct socket_target
+{
+   unsigned port;
+   const char *server;
+   enum socket_domain domain;
+   enum socket_protocol prot;
+} socket_target_t;
+
+int socket_init(void **address, uint16_t port, const char *server,
+      enum socket_type type, int family);
+
+int socket_next(void **address);
+
+int socket_close(int fd);
+
+bool socket_set_block(int fd, bool block);
+
+/* TODO: all callers should be converted to socket_set_block() */
+bool socket_nonblock(int fd);
+
+int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
+      fd_set *errorfds, struct timeval *timeout);
+
+#ifdef NETWORK_HAVE_POLL
+int socket_poll(struct pollfd *fds, unsigned nfds, int timeout);
+#endif
+
+bool socket_wait(int fd, bool *rd, bool *wr, int timeout);
+
+bool socket_send_all_blocking(int fd, const void *data_, size_t size, bool no_signal);
+
+bool socket_send_all_blocking_with_timeout(int fd,
+      const void *data_, size_t size,
+      int timeout, bool no_signal);
+
+ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t size,
+      bool no_signal);
+
+bool socket_receive_all_blocking(int fd, void *data_, size_t size);
+
+bool socket_receive_all_blocking_with_timeout(int fd,
+      void *data_, size_t size,
+      int timeout);
+
+ssize_t socket_receive_all_nonblocking(int fd, bool *error,
+      void *data_, size_t size);
+
+bool socket_bind(int fd, void *data);
+
+int socket_connect(int fd, void *data);
+
+bool socket_connect_with_timeout(int fd, void *data, int timeout);
+
+int socket_create(
+      const char *name,
+      enum socket_domain domain_type,
+      enum socket_type socket_type,
+      enum socket_protocol protocol_type);
+
+void socket_set_target(void *data, socket_target_t *in_addr);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/net/net_socket_ssl.h b/deps/libretro-common/include/net/net_socket_ssl.h
new file mode 100644 (file)
index 0000000..57e2627
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_socket.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_NET_SOCKET_SSL_H
+#define _LIBRETRO_SDK_NET_SOCKET_SSL_H
+
+#include <stdlib.h>
+#include <boolean.h>
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+void* ssl_socket_init(int fd, const char *domain);
+
+int ssl_socket_connect(void *state_data, void *data, bool timeout_enable, bool nonblock);
+
+int ssl_socket_send_all_blocking(void *state_data, const void *data_, size_t size, bool no_signal);
+
+ssize_t ssl_socket_send_all_nonblocking(void *state_data, const void *data_, size_t size, bool no_signal);
+
+int ssl_socket_receive_all_blocking(void *state_data, void *data_, size_t size);
+
+ssize_t ssl_socket_receive_all_nonblocking(void *state_data, bool *error, void *data_, size_t size);
+
+void ssl_socket_close(void *state_data);
+
+void ssl_socket_free(void *state_data);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/playlists/label_sanitization.h b/deps/libretro-common/include/playlists/label_sanitization.h
new file mode 100644 (file)
index 0000000..63ded8c
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (label_sanitization.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stddef.h>
+#include <boolean.h>
+
+/**
+ * label_sanitize:
+ *
+ * NOTE: Does not work with nested blocks.
+ **/
+void label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*));
+
+void label_remove_parens(char *label);
+
+void label_remove_brackets(char *label);
+
+void label_remove_parens_and_brackets(char *label);
+
+void label_keep_region(char *label);
+
+void label_keep_disc(char *label);
+
+void label_keep_region_and_disc(char *label);
diff --git a/deps/libretro-common/include/queues/fifo_queue.h b/deps/libretro-common/include/queues/fifo_queue.h
new file mode 100644 (file)
index 0000000..7a27b04
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fifo_queue.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FIFO_BUFFER_H
+#define __LIBRETRO_SDK_FIFO_BUFFER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <retro_common_api.h>
+#include <retro_inline.h>
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+#define FIFO_READ_AVAIL(buffer) (((buffer)->end + (((buffer)->end < (buffer)->first) ? (buffer)->size : 0)) - (buffer)->first)
+
+#define FIFO_WRITE_AVAIL(buffer) (((buffer)->size - 1) - (((buffer)->end + (((buffer)->end < (buffer)->first) ? (buffer)->size : 0)) - (buffer)->first))
+
+#define FIFO_READ_AVAIL_NONPTR(buffer) (((buffer).end + (((buffer).end < (buffer).first) ? (buffer).size : 0)) - (buffer).first)
+
+#define FIFO_WRITE_AVAIL_NONPTR(buffer) (((buffer).size - 1) - (((buffer).end + (((buffer).end < (buffer).first) ? (buffer).size : 0)) - (buffer).first))
+
+struct fifo_buffer
+{
+   uint8_t *buffer;
+   size_t size;
+   size_t first;
+   size_t end;
+};
+
+typedef struct fifo_buffer fifo_buffer_t;
+
+fifo_buffer_t *fifo_new(size_t size);
+
+bool fifo_initialize(fifo_buffer_t *buf, size_t size);
+
+static INLINE void fifo_clear(fifo_buffer_t *buffer)
+{
+   buffer->first = 0;
+   buffer->end   = 0;
+}
+
+void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size);
+
+void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size);
+
+void fifo_free(fifo_buffer_t *buffer);
+
+bool fifo_deinitialize(fifo_buffer_t *buffer);
+
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/queues/generic_queue.h b/deps/libretro-common/include/queues/generic_queue.h
new file mode 100644 (file)
index 0000000..698d7b6
--- /dev/null
@@ -0,0 +1,208 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (generic_queue.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_GENERIC_QUEUE_H
+#define __LIBRETRO_SDK_GENERIC_QUEUE_H
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+#include <stddef.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * Represents a generic queue. Can contain any number of elements. Each element contains
+ * a value of type "void *". Can be used as a FIFO or LIFO queue.
+ */
+typedef struct generic_queue generic_queue_t;
+
+/**
+ * Represents an iterator for iterating over a queue.
+ */
+typedef struct generic_queue_iterator generic_queue_iterator_t;
+
+/**
+ * Creates a new queue with no elements.
+ *
+ * @return New queue
+ */
+generic_queue_t *generic_queue_new(void);
+
+/**
+ * @brief frees the memory used by the queue
+ * 
+ * Frees all of the memory used by this queue. The values of all
+ * remaining elements are freed using the "free_value" function. Does
+ * nothing if "queue" is NULL.
+ *
+ * @param queue queue to free
+ * @param free_value function to use to free remaining values
+ */
+void generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value));
+
+/**
+ * @brief Push a new value onto the queue
+ *
+ * Pushes a new value onto the end of the queue. Does nothing if "queue"
+ * is NULL.
+ *
+ * @param queue queue to the push the value onto
+ * @param value value to push onto the queue
+ */
+void generic_queue_push(generic_queue_t *queue, void *value);
+
+/**
+ * @brief Remove the last value from the queue
+ *
+ * Removes the last element from the queue. Does nothing if the queue is
+ * NULL.
+ *
+ * @param queue queue to get the value from
+ * @return value of the last element, NULL if queue is empty or NULL
+ */
+void *generic_queue_pop(generic_queue_t *queue);
+
+/**
+ * @brief Get the last value from the queue
+ *
+ * Returns the value of the last element in the queue. Returns NULL if the
+ * queue is NULL or empty.
+ *
+ * @param queue queue to get the last value from
+ * @return value of the last element or NULL
+ */
+void *generic_queue_peek(generic_queue_t *queue);
+
+/**
+ * @brief Get the first value from the queue
+ *
+ * Returns the value of the first element in the queue. Returns NULL if the
+ * queue is NULL or empty.
+ *
+ * @param queue queue to get the first value from
+ * @return value of the first element or NULL
+ */
+void *generic_queue_peek_first(generic_queue_t *queue);
+
+/**
+ * @brief Push a new value onto the front of the queue
+ *
+ * Pushes a new value onto the front of the queue. Does nothing if "queue"
+ * is NULL.
+ *
+ * @param queue queue to the push the value onto
+ * @param value value to push onto the queue
+ */
+void generic_queue_shift(generic_queue_t *queue, void *value);
+
+/**
+ * @brief Remove the first value from the queue
+ *
+ * Removes the first element from the queue. Does nothing if the queue is
+ * NULL.
+ *
+ * @param queue queue to get the value from
+ * @return value of the last element, NULL if queue is empty or NULL
+ */
+void *generic_queue_unshift(generic_queue_t *queue);
+
+/**
+ * @brief Get the size of the queue
+ *
+ * Returns the number of elements in the queue.
+ *
+ * @param queue queue to get the size of
+ * @return number of elements in the queue, 0 if queue is NULL
+ */
+size_t generic_queue_length(generic_queue_t *queue);
+
+/**
+ * @brief Remove the first element in the queue with the provided value
+ *
+ * Removes the first element with a value matching the provided value. Does
+ * nothing if queue is NULL.
+ *
+ * @param queue queue to remove the element from
+ * @param value value to look for in the queue
+ * @return the value of the element removed, NULL if no element was removed
+ */
+void *generic_queue_remove(generic_queue_t *queue, void *value);
+
+/**
+ * @brief Get an iterator for the queue
+ *
+ * Returns a new iterator for the queue. Can be either a forward or backward
+ * iterator.
+ *
+ * @param queue queue to iterate over
+ * @param forward true for a forward iterator, false for backwards
+ * @return new iterator for the queue in the specified direction, NULL if
+ *         "queue" is NULL
+ */
+generic_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward);
+
+/**
+ * @brief Move to the next element in the queue
+ *
+ * Moves the iterator to the next element in the queue. The direction is
+ * specified when retrieving a new iterator.
+ *
+ * @param iterator iterator for the current element
+ * @return iterator for the next element, NULL if iterator is NULL or "iterator"
+ *         is at the last element
+ */
+generic_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator);
+
+/**
+ * @brief Get the value of the element for the iterator
+ *
+ * Returns the value of the element that the iterator is at.
+ *
+ * @param iterator iterator for the current element
+ * @return value of the element for the iterator
+ */
+void *generic_queue_iterator_value(generic_queue_iterator_t *iterator);
+
+/**
+ * @brief Remove the element that the iterator is at
+ *
+ * Removes the element that the iterator is at. The iterator is updated to the
+ * next element.
+ *
+ * @param iterator iterator for the current element
+ * @return updated iterator or NULL if the last element was removed
+ */
+generic_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator);
+
+/**
+ * @brief Release the memory for the iterator
+ *
+ * Frees the memory for the provided iterator. Does nothing if "iterator" is NULL.
+ *
+ * @param iterator iterator to free
+ */
+void generic_queue_iterator_free(generic_queue_iterator_t *iterator);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/queues/message_queue.h b/deps/libretro-common/include/queues/message_queue.h
new file mode 100644 (file)
index 0000000..d79c064
--- /dev/null
@@ -0,0 +1,156 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (message_queue.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_MSG_QUEUE_H
+#define __LIBRETRO_SDK_MSG_QUEUE_H
+
+#include <stddef.h>
+
+#include <retro_common_api.h>
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+enum message_queue_icon
+{
+   MESSAGE_QUEUE_ICON_DEFAULT = 0 /* default icon is tied to category */
+};
+
+enum message_queue_category
+{
+   MESSAGE_QUEUE_CATEGORY_INFO = 0,
+   MESSAGE_QUEUE_CATEGORY_ERROR,
+   MESSAGE_QUEUE_CATEGORY_WARNING,
+   MESSAGE_QUEUE_CATEGORY_SUCCESS
+};
+
+typedef struct queue_elem
+{
+   char *msg;
+   char *title;
+   unsigned duration;
+   unsigned prio;
+   enum message_queue_icon icon;
+   enum message_queue_category category;
+} queue_elem_t;
+
+typedef struct msg_queue
+{
+   char *tmp_msg;
+   queue_elem_t **elems;
+   size_t ptr;
+   size_t size;
+} msg_queue_t;
+
+typedef struct
+{
+   unsigned duration;
+   unsigned prio;
+   enum message_queue_icon icon;
+   enum message_queue_category category;
+   char msg[1024];
+   char title[1024];
+} msg_queue_entry_t;
+
+/**
+ * msg_queue_new:
+ * @size              : maximum size of message
+ *
+ * Creates a message queue with maximum size different messages.
+ *
+ * Returns: NULL if allocation error, pointer to a message queue
+ * if successful. Has to be freed manually.
+ **/
+msg_queue_t *msg_queue_new(size_t size);
+
+bool msg_queue_initialize(msg_queue_t *queue, size_t size);
+
+/**
+ * msg_queue_push:
+ * @queue             : pointer to queue object
+ * @msg               : message to add to the queue
+ * @prio              : priority level of the message
+ * @duration          : how many times the message can be pulled
+ *                      before it vanishes (E.g. show a message for
+ *                      3 seconds @ 60fps = 180 duration).
+ *
+ * Push a new message onto the queue.
+ **/
+void msg_queue_push(msg_queue_t *queue, const char *msg,
+      unsigned prio, unsigned duration,
+      char *title,
+      enum message_queue_icon icon, enum message_queue_category category);
+
+/**
+ * msg_queue_pull:
+ * @queue             : pointer to queue object
+ *
+ * Pulls highest priority message in queue.
+ *
+ * Returns: NULL if no message in queue, otherwise a string
+ * containing the message.
+ **/
+const char *msg_queue_pull(msg_queue_t *queue);
+
+/**
+ * msg_queue_extract:
+ * @queue             : pointer to queue object
+ * @queue_entry       : pointer to external queue entry struct
+ *
+ * Removes highest priority message from queue, copying
+ * contents into queue_entry struct.
+ *
+ * Returns: false if no messages in queue, otherwise true
+ **/
+bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry);
+
+/**
+ * msg_queue_size:
+ * @queue             : pointer to queue object
+ *
+ * Fetches number of messages in queue.
+ *
+ * Returns: Number of messages in queue.
+ **/
+size_t msg_queue_size(msg_queue_t *queue);
+
+/**
+ * msg_queue_clear:
+ * @queue             : pointer to queue object
+ *
+ * Clears out everything in the queue.
+ **/
+void msg_queue_clear(msg_queue_t *queue);
+
+/**
+ * msg_queue_free:
+ * @queue             : pointer to queue object
+ *
+ * Frees message queue..
+ **/
+void msg_queue_free(msg_queue_t *queue);
+
+bool msg_queue_deinitialize(msg_queue_t *queue);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/queues/task_queue.h b/deps/libretro-common/include/queues/task_queue.h
new file mode 100644 (file)
index 0000000..c91d4a7
--- /dev/null
@@ -0,0 +1,262 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (task_queue.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_TASK_QUEUE_H__
+#define __LIBRETRO_SDK_TASK_QUEUE_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <boolean.h>
+
+#include <retro_common.h>
+#include <retro_common_api.h>
+
+#include <libretro.h>
+
+RETRO_BEGIN_DECLS
+
+enum task_type
+{
+   TASK_TYPE_NONE,
+   /* Only one blocking task can exist in the queue at a time.
+    * Attempts to add a new one while another is running is
+    * ignored.
+    */
+   TASK_TYPE_BLOCKING
+};
+
+typedef struct retro_task retro_task_t;
+typedef void (*retro_task_callback_t)(retro_task_t *task,
+      void *task_data,
+      void *user_data, const char *error);
+
+typedef void (*retro_task_handler_t)(retro_task_t *task);
+
+typedef bool (*retro_task_finder_t)(retro_task_t *task,
+      void *userdata);
+
+typedef void (*retro_task_queue_msg_t)(retro_task_t *task,
+      const char *msg,
+      unsigned prio, unsigned duration, bool flush);
+
+typedef bool (*retro_task_retriever_t)(retro_task_t *task, void *data);
+
+typedef bool (*retro_task_condition_fn_t)(void *data);
+
+typedef struct
+{
+   char *source_file;
+} decompress_task_data_t;
+
+struct retro_task
+{
+   /* when the task should run (0 for as soon as possible) */
+   retro_time_t when;
+
+   retro_task_handler_t  handler;
+
+   /* always called from the main loop */
+   retro_task_callback_t callback;
+
+   /* task cleanup handler to free allocated resources, will
+    * be called immediately after running the main callback */
+   retro_task_handler_t cleanup;
+
+   /* created by the handler, destroyed by the user */
+   void *task_data;
+
+   /* owned by the user */
+   void *user_data;
+
+   /* created and destroyed by the code related to the handler */
+   void *state;
+
+   /* created by task handler; destroyed by main loop
+    * (after calling the callback) */
+   char *error;
+
+   void (*progress_cb)(retro_task_t*);
+
+   /* handler can modify but will be
+    * free()d automatically if non-NULL. */
+   char *title;
+
+   /* frontend userdata
+    * (e.g. associate a sticky notification to a task) */
+   void *frontend_userdata;
+
+   /* don't touch this. */
+   retro_task_t *next;
+
+   /* -1 = unmetered/indeterminate, 0-100 = current progress percentage */
+   int8_t progress;
+
+   /* task identifier */
+   uint32_t ident;
+
+   enum task_type type;
+
+   /* if set to true, frontend will
+   use an alternative look for the
+   task progress display */
+   bool alternative_look;
+
+   /* set to true by the handler to signal
+    * the task has finished executing. */
+   bool finished;
+
+   /* set to true by the task system
+    * to signal the task *must* end. */
+   bool cancelled;
+
+   /* if true no OSD messages will be displayed. */
+   bool mute;
+};
+
+typedef struct task_finder_data
+{
+   retro_task_finder_t func;
+   void *userdata;
+} task_finder_data_t;
+
+typedef struct task_retriever_info
+{
+   struct task_retriever_info *next;
+   void *data;
+} task_retriever_info_t;
+
+typedef struct task_retriever_data
+{
+   task_retriever_info_t *list;
+   retro_task_handler_t handler;
+   retro_task_retriever_t func;
+   size_t element_size;
+} task_retriever_data_t;
+
+void *task_queue_retriever_info_next(task_retriever_info_t **link);
+
+void task_queue_retriever_info_free(task_retriever_info_t *list);
+
+/**
+ * Signals a task to end without waiting for
+ * it to complete. */
+void task_queue_cancel_task(void *task);
+
+void task_set_finished(retro_task_t *task, bool finished);
+
+void task_set_mute(retro_task_t *task, bool mute);
+
+void task_set_error(retro_task_t *task, char *error);
+
+void task_set_progress(retro_task_t *task, int8_t progress);
+
+void task_set_title(retro_task_t *task, char *title);
+
+void task_set_data(retro_task_t *task, void *data);
+
+void task_set_cancelled(retro_task_t *task, bool cancelled);
+
+void task_free_title(retro_task_t *task);
+
+bool task_get_cancelled(retro_task_t *task);
+
+bool task_get_finished(retro_task_t *task);
+
+bool task_get_mute(retro_task_t *task);
+
+char* task_get_error(retro_task_t *task);
+
+int8_t task_get_progress(retro_task_t *task);
+
+char* task_get_title(retro_task_t *task);
+
+void* task_get_data(retro_task_t *task);
+
+bool task_is_on_main_thread(void);
+
+void task_queue_set_threaded(void);
+
+void task_queue_unset_threaded(void);
+
+bool task_queue_is_threaded(void);
+
+/**
+ * Calls func for every running task
+ * until it returns true.
+ * Returns a task or NULL if not found.
+ */
+bool task_queue_find(task_finder_data_t *find_data);
+
+/**
+ * Calls func for every running task when handler
+ * parameter matches task handler, allowing the
+ * list parameter to be filled with user-defined
+ * data.
+ */
+void task_queue_retrieve(task_retriever_data_t *data);
+
+ /* Checks for finished tasks
+  * Takes the finished tasks, if any,
+  * and runs their callbacks.
+  * This must only be called from the main thread. */
+void task_queue_check(void);
+
+/* Pushes a task
+ * The task will start as soon as possible.
+ * If a second blocking task is attempted, false will be returned
+ * and the task will be ignored. */
+bool task_queue_push(retro_task_t *task);
+
+/* Blocks until all non-scheduled tasks have finished.
+ * Will return early if cond is not NULL
+ * and cond(data) returns false.
+ * This must only be called from the main thread. */
+void task_queue_wait(retro_task_condition_fn_t cond, void* data);
+
+/* Sends a signal to terminate all the tasks.
+ *
+ * This won't terminate the tasks immediately.
+ * They will finish as soon as possible.
+ *
+ * This must only be called from the main thread. */
+void task_queue_reset(void);
+
+/* Deinitializes the task system.
+ * This deinitializes the task system.
+ * The tasks that are running at
+ * the moment will stay on hold */
+void task_queue_deinit(void);
+
+/* Initializes the task system.
+ * This initializes the task system
+ * and chooses an appropriate
+ * implementation according to the settings.
+ *
+ * This must only be called from the main thread. */
+void task_queue_init(bool threaded, retro_task_queue_msg_t msg_push);
+
+/* Allocates and inits a new retro_task_t */
+retro_task_t *task_init(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/retro_assert.h b/deps/libretro-common/include/retro_assert.h
new file mode 100644 (file)
index 0000000..79dbb32
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_assert.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __RETRO_ASSERT_H
+#define __RETRO_ASSERT_H
+
+#include <assert.h>
+
+#ifdef RARCH_INTERNAL
+#include <stdio.h>
+#define retro_assert(cond) ((void)( (cond) || (printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__), abort(), 0) ))
+#else
+#define retro_assert(cond) assert(cond)
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/retro_common.h b/deps/libretro-common/include/retro_common.h
new file mode 100644 (file)
index 0000000..a715a28
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_common.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_COMMON_RETRO_COMMON_H
+#define _LIBRETRO_COMMON_RETRO_COMMON_H
+
+/*
+This file is designed to normalize the libretro-common compiling environment.
+It is not to be used in public API headers, as they should be designed as leanly as possible.
+Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable,
+in a public API, you may need this.
+*/
+
+/* conditional compilation is handled inside here */
+#include <compat/msvc.h>
+
+#endif
diff --git a/deps/libretro-common/include/retro_common_api.h b/deps/libretro-common/include/retro_common_api.h
new file mode 100644 (file)
index 0000000..0f68b7d
--- /dev/null
@@ -0,0 +1,119 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_common_api.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_COMMON_RETRO_COMMON_API_H
+#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
+
+/*
+This file is designed to normalize the libretro-common compiling environment
+for public API headers. This should be leaner than a normal compiling environment,
+since it gets #included into other project's sources.
+*/
+
+/* ------------------------------------ */
+
+/*
+Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
+headers to enable them to get used by c++ sources.
+However, we want to support building this library as C++ as well, so a
+special technique is called for.
+*/
+
+#define RETRO_BEGIN_DECLS
+#define RETRO_END_DECLS
+
+#ifdef __cplusplus
+
+#ifdef CXX_BUILD
+/* build wants everything to be built as c++, so no extern "C" */
+#else
+#undef RETRO_BEGIN_DECLS
+#undef RETRO_END_DECLS
+#define RETRO_BEGIN_DECLS extern "C" {
+#define RETRO_END_DECLS }
+#endif
+
+#else
+
+/* header is included by a C source file, so no extern "C" */
+
+#endif
+
+/*
+IMO, this non-standard ssize_t should not be used.
+However, it's a good example of how to handle something like this.
+*/
+#ifdef _MSC_VER
+#ifndef HAVE_SSIZE_T
+#define HAVE_SSIZE_T
+#if defined(_WIN64)
+typedef __int64 ssize_t;
+#elif defined(_WIN32)
+typedef int ssize_t;
+#endif
+#endif
+#elif defined(__MACH__)
+#include <sys/types.h>
+#endif
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+#ifndef PRId64
+#define PRId64 "I64d"
+#define PRIu64 "I64u"
+#define PRIuPTR "Iu"
+#endif
+#endif
+#else
+/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
+/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
+/* https://github.com/libretro/RetroArch/issues/6009 */
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
+#include <inttypes.h>
+#endif
+#ifndef PRId64
+#error "inttypes.h is being screwy"
+#endif
+#define STRING_REP_INT64 "%" PRId64
+#define STRING_REP_UINT64 "%" PRIu64
+#define STRING_REP_USIZE "%" PRIuPTR
+
+/*
+I would like to see retro_inline.h moved in here; possibly boolean too.
+
+rationale: these are used in public APIs, and it is easier to find problems
+and write code that works the first time portably when theyre included uniformly
+than to do the analysis from scratch each time you think you need it, for each feature.
+
+Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
+then you should pay the price everywhere, so you can see how much grief it will cause.
+
+Of course, another school of thought is that you should do as little damage as possible
+in as few places as possible...
+*/
+
+/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
+#endif
diff --git a/deps/libretro-common/include/retro_dirent.h b/deps/libretro-common/include/retro_dirent.h
new file mode 100644 (file)
index 0000000..3b04167
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_dirent.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __RETRO_DIRENT_H
+#define __RETRO_DIRENT_H
+
+#include <libretro.h>
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+#define DIRENT_REQUIRED_VFS_VERSION 3
+
+void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info);
+
+typedef struct RDIR RDIR;
+
+/**
+ *
+ * retro_opendir:
+ * @name         : path to the directory to open.
+ *
+ * Opens a directory for reading. Tidy up with retro_closedir.
+ *
+ * Returns: RDIR pointer on success, NULL if name is not a
+ * valid directory, null itself or the empty string.
+ */
+struct RDIR *retro_opendir(const char *name);
+
+struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden);
+
+int retro_readdir(struct RDIR *rdir);
+
+/* Deprecated, returns false, left for compatibility */
+bool retro_dirent_error(struct RDIR *rdir);
+
+const char *retro_dirent_get_name(struct RDIR *rdir);
+
+/**
+ *
+ * retro_dirent_is_dir:
+ * @rdir         : pointer to the directory entry.
+ * @unused       : deprecated, included for compatibility reasons, pass NULL
+ *
+ * Is the directory listing entry a directory?
+ *
+ * Returns: true if directory listing entry is
+ * a directory, false if not.
+ */
+bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused);
+
+void retro_closedir(struct RDIR *rdir);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/retro_endianness.h b/deps/libretro-common/include/retro_endianness.h
new file mode 100644 (file)
index 0000000..4698463
--- /dev/null
@@ -0,0 +1,580 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_endianness.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_ENDIANNESS_H
+#define __LIBRETRO_SDK_ENDIANNESS_H
+
+#include <retro_inline.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(_MSC_VER) && _MSC_VER > 1200
+#define SWAP16 _byteswap_ushort
+#define SWAP32 _byteswap_ulong
+#else
+static INLINE uint16_t SWAP16(uint16_t x)
+{
+  return ((x & 0x00ff) << 8) |
+         ((x & 0xff00) >> 8);
+}
+
+static INLINE uint32_t SWAP32(uint32_t x)
+{
+  return ((x & 0x000000ff) << 24) |
+         ((x & 0x0000ff00) <<  8) |
+         ((x & 0x00ff0000) >>  8) |
+         ((x & 0xff000000) >> 24);
+}
+
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+static INLINE uint64_t SWAP64(uint64_t val)
+{
+  return
+      ((val & 0x00000000000000ff) << 56)
+    | ((val & 0x000000000000ff00) << 40)
+    | ((val & 0x0000000000ff0000) << 24)
+    | ((val & 0x00000000ff000000) << 8)
+    | ((val & 0x000000ff00000000) >> 8)
+    | ((val & 0x0000ff0000000000) >> 24)
+    | ((val & 0x00ff000000000000) >> 40)
+    | ((val & 0xff00000000000000) >> 56);
+}
+#else
+static INLINE uint64_t SWAP64(uint64_t val)
+{
+  return   ((val & 0x00000000000000ffULL) << 56)
+        | ((val & 0x000000000000ff00ULL) << 40)
+        | ((val & 0x0000000000ff0000ULL) << 24)
+        | ((val & 0x00000000ff000000ULL) << 8)
+        | ((val & 0x000000ff00000000ULL) >> 8)
+        | ((val & 0x0000ff0000000000ULL) >> 24)
+        | ((val & 0x00ff000000000000ULL) >> 40)
+         | ((val & 0xff00000000000000ULL) >> 56);
+}
+#endif
+
+#ifdef _MSC_VER
+/* MSVC pre-defines macros depending on target arch */
+#if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_M_ARM64)
+#ifndef LSB_FIRST
+#define LSB_FIRST 1
+#endif
+#elif _M_PPC
+#ifndef MSB_FIRST
+#define MSB_FIRST 1
+#endif
+#else
+/* MSVC can run on _M_ALPHA and _M_IA64 too, but they're both bi-endian; need to find what mode MSVC runs them at */
+#error "unknown platform, can't determine endianness"
+#endif
+#else
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#ifndef MSB_FIRST
+#define MSB_FIRST 1
+#endif
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#ifndef LSB_FIRST
+#define LSB_FIRST 1
+#endif
+#else
+#error "Invalid endianness macros"
+#endif
+#endif
+
+#if defined(MSB_FIRST) && defined(LSB_FIRST)
+#  error "Bug in LSB_FIRST/MSB_FIRST definition"
+#endif
+
+#if !defined(MSB_FIRST) && !defined(LSB_FIRST)
+#  error "Bug in LSB_FIRST/MSB_FIRST definition"
+#endif
+
+#ifdef MSB_FIRST
+#  define RETRO_IS_BIG_ENDIAN 1
+#  define RETRO_IS_LITTLE_ENDIAN 0
+/* For compatibility */
+#  define WORDS_BIGENDIAN 1
+#else
+#  define RETRO_IS_BIG_ENDIAN 0
+#  define RETRO_IS_LITTLE_ENDIAN 1
+/* For compatibility */
+#  undef WORDS_BIGENDIAN
+#endif
+
+
+/**
+ * is_little_endian:
+ *
+ * Checks if the system is little endian or big-endian.
+ *
+ * Returns: greater than 0 if little-endian,
+ * otherwise big-endian.
+ **/
+#define is_little_endian() RETRO_IS_LITTLE_ENDIAN
+
+/**
+ * swap_if_big64:
+ * @val        : unsigned 64-bit value
+ *
+ * Byteswap unsigned 64-bit value if system is big-endian.
+ *
+ * Returns: Byteswapped value in case system is big-endian,
+ * otherwise returns same value.
+ **/
+
+#if RETRO_IS_BIG_ENDIAN
+#define swap_if_big64(val) (SWAP64(val))
+#elif RETRO_IS_LITTLE_ENDIAN
+#define swap_if_big64(val) (val)
+#endif
+
+/**
+ * swap_if_big32:
+ * @val        : unsigned 32-bit value
+ *
+ * Byteswap unsigned 32-bit value if system is big-endian.
+ *
+ * Returns: Byteswapped value in case system is big-endian,
+ * otherwise returns same value.
+ **/
+
+#if RETRO_IS_BIG_ENDIAN
+#define swap_if_big32(val) (SWAP32(val))
+#elif RETRO_IS_LITTLE_ENDIAN
+#define swap_if_big32(val) (val)
+#endif
+
+/**
+ * swap_if_little64:
+ * @val        : unsigned 64-bit value
+ *
+ * Byteswap unsigned 64-bit value if system is little-endian.
+ *
+ * Returns: Byteswapped value in case system is little-endian,
+ * otherwise returns same value.
+ **/
+
+#if RETRO_IS_BIG_ENDIAN
+#define swap_if_little64(val) (val)
+#elif RETRO_IS_LITTLE_ENDIAN
+#define swap_if_little64(val) (SWAP64(val))
+#endif
+
+/**
+ * swap_if_little32:
+ * @val        : unsigned 32-bit value
+ *
+ * Byteswap unsigned 32-bit value if system is little-endian.
+ *
+ * Returns: Byteswapped value in case system is little-endian,
+ * otherwise returns same value.
+ **/
+
+#if RETRO_IS_BIG_ENDIAN
+#define swap_if_little32(val) (val)
+#elif RETRO_IS_LITTLE_ENDIAN
+#define swap_if_little32(val) (SWAP32(val))
+#endif
+
+/**
+ * swap_if_big16:
+ * @val        : unsigned 16-bit value
+ *
+ * Byteswap unsigned 16-bit value if system is big-endian.
+ *
+ * Returns: Byteswapped value in case system is big-endian,
+ * otherwise returns same value.
+ **/
+
+#if RETRO_IS_BIG_ENDIAN
+#define swap_if_big16(val) (SWAP16(val))
+#elif RETRO_IS_LITTLE_ENDIAN
+#define swap_if_big16(val) (val)
+#endif
+
+/**
+ * swap_if_little16:
+ * @val        : unsigned 16-bit value
+ *
+ * Byteswap unsigned 16-bit value if system is little-endian.
+ *
+ * Returns: Byteswapped value in case system is little-endian,
+ * otherwise returns same value.
+ **/
+
+#if RETRO_IS_BIG_ENDIAN
+#define swap_if_little16(val) (val)
+#elif RETRO_IS_LITTLE_ENDIAN
+#define swap_if_little16(val) (SWAP16(val))
+#endif
+
+/**
+ * store32be:
+ * @addr        : pointer to unsigned 32-bit buffer
+ * @data        : unsigned 32-bit value to write
+ *
+ * Write data to address. Endian-safe. Byteswaps the data
+ * first if necessary before storing it.
+ **/
+static INLINE void store32be(uint32_t *addr, uint32_t data)
+{
+   *addr = swap_if_little32(data);
+}
+
+/**
+ * load32be:
+ * @addr        : pointer to unsigned 32-bit buffer
+ *
+ * Load value from address. Endian-safe.
+ *
+ * Returns: value from address, byte-swapped if necessary.
+ **/
+static INLINE uint32_t load32be(const uint32_t *addr)
+{
+   return swap_if_little32(*addr);
+}
+
+/**
+ * retro_cpu_to_le16:
+ * @val        : unsigned 16-bit value
+ *
+ * Convert unsigned 16-bit value from system to little-endian.
+ *
+ * Returns: Little-endian representation of val.
+ **/
+
+#define retro_cpu_to_le16(val) swap_if_big16(val)
+
+/**
+ * retro_cpu_to_le32:
+ * @val        : unsigned 32-bit value
+ *
+ * Convert unsigned 32-bit value from system to little-endian.
+ *
+ * Returns: Little-endian representation of val.
+ **/
+
+#define retro_cpu_to_le32(val) swap_if_big32(val)
+
+/**
+ * retro_cpu_to_le64:
+ * @val        : unsigned 64-bit value
+ *
+ * Convert unsigned 64-bit value from system to little-endian.
+ *
+ * Returns: Little-endian representation of val.
+ **/
+
+#define retro_cpu_to_le64(val) swap_if_big64(val)
+
+/**
+ * retro_le_to_cpu16:
+ * @val        : unsigned 16-bit value
+ *
+ * Convert unsigned 16-bit value from little-endian to native.
+ *
+ * Returns: Native representation of little-endian val.
+ **/
+
+#define retro_le_to_cpu16(val) swap_if_big16(val)
+
+/**
+ * retro_le_to_cpu32:
+ * @val        : unsigned 32-bit value
+ *
+ * Convert unsigned 32-bit value from little-endian to native.
+ *
+ * Returns: Native representation of little-endian val.
+ **/
+
+#define retro_le_to_cpu32(val) swap_if_big32(val)
+
+/**
+ * retro_le_to_cpu16:
+ * @val        : unsigned 64-bit value
+ *
+ * Convert unsigned 64-bit value from little-endian to native.
+ *
+ * Returns: Native representation of little-endian val.
+ **/
+
+#define retro_le_to_cpu64(val) swap_if_big64(val)
+
+/**
+ * retro_cpu_to_be16:
+ * @val        : unsigned 16-bit value
+ *
+ * Convert unsigned 16-bit value from system to big-endian.
+ *
+ * Returns: Big-endian representation of val.
+ **/
+
+#define retro_cpu_to_be16(val) swap_if_little16(val)
+
+/**
+ * retro_cpu_to_be32:
+ * @val        : unsigned 32-bit value
+ *
+ * Convert unsigned 32-bit value from system to big-endian.
+ *
+ * Returns: Big-endian representation of val.
+ **/
+
+#define retro_cpu_to_be32(val) swap_if_little32(val)
+
+/**
+ * retro_cpu_to_be64:
+ * @val        : unsigned 64-bit value
+ *
+ * Convert unsigned 64-bit value from system to big-endian.
+ *
+ * Returns: Big-endian representation of val.
+ **/
+
+#define retro_cpu_to_be64(val) swap_if_little64(val)
+
+/**
+ * retro_be_to_cpu16:
+ * @val        : unsigned 16-bit value
+ *
+ * Convert unsigned 16-bit value from big-endian to native.
+ *
+ * Returns: Native representation of big-endian val.
+ **/
+
+#define retro_be_to_cpu16(val) swap_if_little16(val)
+
+/**
+ * retro_be_to_cpu32:
+ * @val        : unsigned 32-bit value
+ *
+ * Convert unsigned 32-bit value from big-endian to native.
+ *
+ * Returns: Native representation of big-endian val.
+ **/
+
+#define retro_be_to_cpu32(val) swap_if_little32(val)
+
+/**
+ * retro_be_to_cpu64:
+ * @val        : unsigned 64-bit value
+ *
+ * Convert unsigned 64-bit value from big-endian to native.
+ *
+ * Returns: Native representation of big-endian val.
+ **/
+
+#define retro_be_to_cpu64(val) swap_if_little64(val)
+
+#ifdef  __GNUC__
+/* This attribute means that the same memory may be referred through
+   pointers to different size of the object (aliasing). E.g. that u8 *
+   and u32 * may actually be pointing to the same object.  */
+#define MAY_ALIAS  __attribute__((__may_alias__))
+#else
+#define MAY_ALIAS
+#endif
+
+#pragma pack(push, 1)
+struct retro_unaligned_uint16_s
+{
+  uint16_t val;
+} MAY_ALIAS;
+struct retro_unaligned_uint32_s
+{
+  uint32_t val;
+} MAY_ALIAS;
+struct retro_unaligned_uint64_s
+{
+  uint64_t val;
+} MAY_ALIAS;
+#pragma pack(pop)
+
+typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;
+typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;
+typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;
+
+/* L-value references to unaligned pointers.  */
+#define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)->val)
+#define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)->val)
+#define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)->val)
+
+/**
+ * retro_get_unaligned_16be:
+ * @addr        : pointer to unsigned 16-bit value
+ *
+ * Convert unsigned unaligned 16-bit value from big-endian to native.
+ *
+ * Returns: Native representation of big-endian val.
+ **/
+
+static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
+  return retro_be_to_cpu16(retro_unaligned16(addr));
+}
+
+/**
+ * retro_get_unaligned_32be:
+ * @addr        : pointer to unsigned 32-bit value
+ *
+ * Convert unsigned unaligned 32-bit value from big-endian to native.
+ *
+ * Returns: Native representation of big-endian val.
+ **/
+
+static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
+  return retro_be_to_cpu32(retro_unaligned32(addr));
+}
+
+/**
+ * retro_get_unaligned_64be:
+ * @addr        : pointer to unsigned 64-bit value
+ *
+ * Convert unsigned unaligned 64-bit value from big-endian to native.
+ *
+ * Returns: Native representation of big-endian val.
+ **/
+
+static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
+  return retro_be_to_cpu64(retro_unaligned64(addr));
+}
+
+/**
+ * retro_get_unaligned_16le:
+ * @addr        : pointer to unsigned 16-bit value
+ *
+ * Convert unsigned unaligned 16-bit value from little-endian to native.
+ *
+ * Returns: Native representation of little-endian val.
+ **/
+
+static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
+  return retro_le_to_cpu16(retro_unaligned16(addr));
+}
+
+/**
+ * retro_get_unaligned_32le:
+ * @addr        : pointer to unsigned 32-bit value
+ *
+ * Convert unsigned unaligned 32-bit value from little-endian to native.
+ *
+ * Returns: Native representation of little-endian val.
+ **/
+
+static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
+  return retro_le_to_cpu32(retro_unaligned32(addr));
+}
+
+/**
+ * retro_get_unaligned_64le:
+ * @addr        : pointer to unsigned 64-bit value
+ *
+ * Convert unsigned unaligned 64-bit value from little-endian to native.
+ *
+ * Returns: Native representation of little-endian val.
+ **/
+
+static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
+  return retro_le_to_cpu64(retro_unaligned64(addr));
+}
+
+/**
+ * retro_set_unaligned_16le:
+ * @addr        : pointer to unsigned 16-bit value
+ * @val         : value to store
+ *
+ * Convert native value to unsigned unaligned 16-bit little-endian value
+ *
+ **/
+
+static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v) {
+  retro_unaligned16(addr) = retro_cpu_to_le16(v);
+}
+
+/**
+ * retro_set_unaligned_32le:
+ * @addr        : pointer to unsigned 32-bit value
+ * @val         : value to store
+ *
+ * Convert native value to unsigned unaligned 32-bit little-endian value
+ *
+ **/
+
+static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v) {
+  retro_unaligned32(addr) = retro_cpu_to_le32(v);
+}
+
+/**
+ * retro_set_unaligned_32le:
+ * @addr        : pointer to unsigned 32-bit value
+ * @val         : value to store
+ *
+ * Convert native value to unsigned unaligned 32-bit little-endian value
+ *
+ **/
+
+static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v) {
+  retro_unaligned64(addr) = retro_cpu_to_le64(v);
+}
+
+/**
+ * retro_set_unaligned_16be:
+ * @addr        : pointer to unsigned 16-bit value
+ * @val         : value to store
+ *
+ * Convert native value to unsigned unaligned 16-bit big-endian value
+ *
+ **/
+
+static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v) {
+  retro_unaligned16(addr) = retro_cpu_to_be16(v);
+}
+
+/**
+ * retro_set_unaligned_32be:
+ * @addr        : pointer to unsigned 32-bit value
+ * @val         : value to store
+ *
+ * Convert native value to unsigned unaligned 32-bit big-endian value
+ *
+ **/
+
+static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v) {
+  retro_unaligned32(addr) = retro_cpu_to_be32(v);
+}
+
+/**
+ * retro_set_unaligned_32be:
+ * @addr        : pointer to unsigned 32-bit value
+ * @val         : value to store
+ *
+ * Convert native value to unsigned unaligned 32-bit big-endian value
+ *
+ **/
+
+static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v) {
+  retro_unaligned64(addr) = retro_cpu_to_be64(v);
+}
+
+
+#endif
diff --git a/deps/libretro-common/include/retro_environment.h b/deps/libretro-common/include/retro_environment.h
new file mode 100644 (file)
index 0000000..1389eb5
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_environment.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_ENVIRONMENT_H
+#define __LIBRETRO_SDK_ENVIRONMENT_H
+
+/*
+This file is designed to create a normalized environment for compiling
+libretro-common's private implementations, or any other sources which might
+enjoy use of it's environment (RetroArch for instance).
+This should be an elaborately crafted environment so that sources don't
+need to be full of platform-specific workarounds.
+*/
+
+#if defined (__cplusplus)
+#if 0
+printf("This is C++, version %d.\n", __cplusplus);
+#endif
+/* The expected values would be
+ *   199711L, for ISO/IEC 14882:1998 or 14882:2003
+ */
+
+#elif defined(__STDC__)
+/* This is standard C. */
+
+#if (__STDC__ == 1)
+/* The implementation is ISO-conforming. */
+#define __STDC_ISO__
+#else
+/* The implementation is not ISO-conforming. */
+#endif
+
+#if defined(__STDC_VERSION__)
+#if (__STDC_VERSION__ >= 201112L)
+/* This is C11. */
+#define __STDC_C11__
+#elif (__STDC_VERSION__ >= 199901L)
+/* This is C99. */
+#define __STDC_C99__
+#elif (__STDC_VERSION__ >= 199409L)
+/* This is C89 with amendment 1. */
+#define __STDC_C89__
+#define __STDC_C89_AMENDMENT_1__
+#else
+/* This is C89 without amendment 1. */
+#define __STDC_C89__
+#endif
+#else /* !defined(__STDC_VERSION__) */
+/* This is C89. __STDC_VERSION__ is not defined. */
+#define __STDC_C89__
+#endif
+
+#else   /* !defined(__STDC__) */
+/* This is not standard C. __STDC__ is not defined. */
+#endif
+
+#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+/* Try to find out if we're compiling for WinRT or non-WinRT */
+#if defined(_MSC_VER) && defined(__has_include)
+#if __has_include(<winapifamily.h>)
+#define HAVE_WINAPIFAMILY_H 1
+#else
+#define HAVE_WINAPIFAMILY_H 0
+#endif
+
+/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
+#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */
+#define HAVE_WINAPIFAMILY_H 1
+#else
+#define HAVE_WINAPIFAMILY_H 0
+#endif
+
+#if HAVE_WINAPIFAMILY_H
+#include <winapifamily.h>
+#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
+#else
+#define WINAPI_FAMILY_WINRT 0
+#endif /* HAVE_WINAPIFAMILY_H */
+
+#if WINAPI_FAMILY_WINRT
+#undef __WINRT__
+#define __WINRT__ 1
+#endif
+
+/* MSVC obviously has to have some non-standard constants... */
+#if _M_IX86_FP == 1
+#define __SSE__ 1
+#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))
+#define __SSE__ 1
+#define __SSE2__ 1
+#endif
+
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/retro_inline.h b/deps/libretro-common/include/retro_inline.h
new file mode 100644 (file)
index 0000000..b27d6dd
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_inline.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_INLINE_H
+#define __LIBRETRO_SDK_INLINE_H
+
+#ifndef INLINE
+
+#if defined(_WIN32) || defined(__INTEL_COMPILER)
+#define INLINE __inline
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
+#define INLINE inline
+#elif defined(__GNUC__)
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+
+#endif
+#endif
diff --git a/deps/libretro-common/include/retro_math.h b/deps/libretro-common/include/retro_math.h
new file mode 100644 (file)
index 0000000..d1cb862
--- /dev/null
@@ -0,0 +1,190 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_math.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_COMMON_MATH_H
+#define _LIBRETRO_COMMON_MATH_H
+
+#include <stdint.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#elif defined(_WIN32) && defined(_XBOX)
+#include <Xtl.h>
+#endif
+
+#include <limits.h>
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+#include <retro_inline.h>
+
+#ifndef M_PI
+#if !defined(USE_MATH_DEFINES)
+#define M_PI 3.14159265358979323846264338327
+#endif
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/**
+ * next_pow2:
+ * @v         : initial value
+ *
+ * Get next power of 2 value based on  initial value.
+ *
+ * Returns: next power of 2 value (derived from @v).
+ **/
+static INLINE uint32_t next_pow2(uint32_t v)
+{
+   v--;
+   v |= v >> 1;
+   v |= v >> 2;
+   v |= v >> 4;
+   v |= v >> 8;
+   v |= v >> 16;
+   v++;
+   return v;
+}
+
+/**
+ * prev_pow2:
+ * @v         : initial value
+ *
+ * Get previous power of 2 value based on initial value.
+ *
+ * Returns: previous power of 2 value (derived from @v).
+ **/
+static INLINE uint32_t prev_pow2(uint32_t v)
+{
+   v |= v >> 1;
+   v |= v >> 2;
+   v |= v >> 4;
+   v |= v >> 8;
+   v |= v >> 16;
+   return v - (v >> 1);
+}
+
+/**
+ * clamp:
+ * @v         : initial value
+ *
+ * Get the clamped value based on initial value.
+ *
+ * Returns: clamped value (derived from @v).
+ **/
+static INLINE float clamp_value(float v, float min, float max)
+{
+   return v <= min ? min : v >= max ? max : v;
+}
+
+/**
+ * saturate_value:
+ * @v         : initial value
+ *
+ * Get the clamped 0.0-1.0 value based on initial value.
+ *
+ * Returns: clamped 0.0-1.0 value (derived from @v).
+ **/
+static INLINE float saturate_value(float v)
+{
+   return clamp_value(v, 0.0f, 1.0f);
+}
+
+/**
+ * dot_product:
+ * @a         : left hand vector value
+ * @b         : right hand vector value
+ *
+ * Get the dot product of the two passed in vectors.
+ *
+ * Returns: dot product value (derived from @a and @b).
+ **/
+static INLINE float dot_product(const float* a, const float* b) 
+{
+   return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
+}
+
+/**
+ * convert_rgb_to_yxy:
+ * @rgb         : in RGB colour space value
+ * @Yxy         : out Yxy colour space value
+ *
+ * Convert from RGB colour space to Yxy colour space.
+ *
+ * Returns: Yxy colour space value (derived from @rgb).
+ **/
+static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy) 
+{
+   float inv;
+   float xyz[3];
+   float one[3]        = {1.0, 1.0, 1.0};
+   float rgb_xyz[3][3] = {
+      {0.4124564, 0.3575761, 0.1804375},
+      {0.2126729, 0.7151522, 0.0721750},
+      {0.0193339, 0.1191920, 0.9503041}
+   };
+
+   xyz[0]              = dot_product(rgb_xyz[0], rgb);
+   xyz[1]              = dot_product(rgb_xyz[1], rgb);
+   xyz[2]              = dot_product(rgb_xyz[2], rgb);
+
+   inv                 = 1.0f / dot_product(xyz, one);
+   Yxy[0]              = xyz[1]; 
+   Yxy[1]              = xyz[0] * inv;
+   Yxy[2]              = xyz[1] * inv;
+}
+/**
+ * convert_yxy_to_rgb:
+ * @rgb         : in Yxy colour space value
+ * @Yxy         : out rgb colour space value
+ *
+ * Convert from Yxy colour space to rgb colour space.
+ *
+ * Returns: rgb colour space value (derived from @Yxy).
+ **/
+static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
+{
+   float xyz[3];
+   float xyz_rgb[3][3] = {
+      {3.2404542, -1.5371385, -0.4985314},
+      {-0.9692660, 1.8760108,  0.0415560},
+      {0.0556434, -0.2040259, 1.0572252}
+   };
+   xyz[0]              = Yxy[0] * Yxy[1] / Yxy[2];
+   xyz[1]              = Yxy[0];
+   xyz[2]              = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];
+
+   rgb[0]              = dot_product(xyz_rgb[0], xyz);
+   rgb[1]              = dot_product(xyz_rgb[1], xyz);
+   rgb[2]              = dot_product(xyz_rgb[2], xyz);
+}
+
+#endif
diff --git a/deps/libretro-common/include/retro_miscellaneous.h b/deps/libretro-common/include/retro_miscellaneous.h
new file mode 100644 (file)
index 0000000..953ab18
--- /dev/null
@@ -0,0 +1,222 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_miscellaneous.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __RARCH_MISCELLANEOUS_H
+#define __RARCH_MISCELLANEOUS_H
+
+#define RARCH_MAX_SUBSYSTEMS 10
+#define RARCH_MAX_SUBSYSTEM_ROMS 10
+
+#include <stdint.h>
+#include <boolean.h>
+#include <retro_inline.h>
+
+#if defined(_WIN32)
+
+#if defined(_XBOX)
+#include <Xtl.h>
+#else
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
+#endif
+
+#include <limits.h>
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+
+#ifdef IOS
+#include <sys/param.h>
+#endif
+
+static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i < count;i++)
+      a[i] |= b[i];
+}
+
+static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i < count;i++)
+      a[i] &= ~b[i];
+}
+
+static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i < count; i++)
+   {
+      if (ptr[i] != 0)
+         return true;
+   }
+   return false;
+}
+
+static INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i < count; i++)
+   {
+      if (a[i] != b[i])
+         return true;
+   }
+   return false;
+}
+
+#ifndef PATH_MAX_LENGTH
+#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__)
+#define PATH_MAX_LENGTH 512
+#else
+#define PATH_MAX_LENGTH 4096
+#endif
+#endif
+
+#ifndef NAME_MAX_LENGTH
+#define NAME_MAX_LENGTH 256
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ARRAY_SIZE(a)              (sizeof(a) / sizeof((a)[0]))
+
+#define BITS_GET_ELEM(a, i)        ((a).data[i])
+#define BITS_GET_ELEM_PTR(a, i)    ((a)->data[i])
+
+#define BIT_SET(a, bit)   ((a)[(bit) >> 3] |=  (1 << ((bit) & 7)))
+#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
+#define BIT_GET(a, bit)   (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
+
+#define BIT16_SET(a, bit)    ((a) |=  (1 << ((bit) & 15)))
+#define BIT16_CLEAR(a, bit)  ((a) &= ~(1 << ((bit) & 15)))
+#define BIT16_GET(a, bit)    (((a) >> ((bit) & 15)) & 1)
+#define BIT16_CLEAR_ALL(a)   ((a) = 0)
+
+#define BIT32_SET(a, bit)    ((a) |=  (UINT32_C(1) << ((bit) & 31)))
+#define BIT32_CLEAR(a, bit)  ((a) &= ~(UINT32_C(1) << ((bit) & 31)))
+#define BIT32_GET(a, bit)    (((a) >> ((bit) & 31)) & 1)
+#define BIT32_CLEAR_ALL(a)   ((a) = 0)
+
+#define BIT64_SET(a, bit)    ((a) |=  (UINT64_C(1) << ((bit) & 63)))
+#define BIT64_CLEAR(a, bit)  ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
+#define BIT64_GET(a, bit)    (((a) >> ((bit) & 63)) & 1)
+#define BIT64_CLEAR_ALL(a)   ((a) = 0)
+
+#define BIT128_SET(a, bit)   ((a).data[(bit) >> 5] |=  (UINT32_C(1) << ((bit) & 31)))
+#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))
+#define BIT128_GET(a, bit)   (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
+#define BIT128_CLEAR_ALL(a)  memset(&(a), 0, sizeof(a))
+
+#define BIT128_SET_PTR(a, bit)   BIT128_SET(*a, bit)
+#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
+#define BIT128_GET_PTR(a, bit)   BIT128_GET(*a, bit)
+#define BIT128_CLEAR_ALL_PTR(a)  BIT128_CLEAR_ALL(*a)
+
+#define BIT256_SET(a, bit)       BIT128_SET(a, bit)
+#define BIT256_CLEAR(a, bit)     BIT128_CLEAR(a, bit)
+#define BIT256_GET(a, bit)       BIT128_GET(a, bit)
+#define BIT256_CLEAR_ALL(a)      BIT128_CLEAR_ALL(a)
+
+#define BIT256_SET_PTR(a, bit)   BIT256_SET(*a, bit)
+#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
+#define BIT256_GET_PTR(a, bit)   BIT256_GET(*a, bit)
+#define BIT256_CLEAR_ALL_PTR(a)  BIT256_CLEAR_ALL(*a)
+
+#define BIT512_SET(a, bit)       BIT256_SET(a, bit)
+#define BIT512_CLEAR(a, bit)     BIT256_CLEAR(a, bit)
+#define BIT512_GET(a, bit)       BIT256_GET(a, bit)
+#define BIT512_CLEAR_ALL(a)      BIT256_CLEAR_ALL(a)
+
+#define BIT512_SET_PTR(a, bit)   BIT512_SET(*a, bit)
+#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)
+#define BIT512_GET_PTR(a, bit)   BIT512_GET(*a, bit)
+#define BIT512_CLEAR_ALL_PTR(a)  BIT512_CLEAR_ALL(*a)
+
+#define BITS_COPY16_PTR(a,bits) \
+{ \
+   BIT128_CLEAR_ALL_PTR(a); \
+   BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
+}
+
+#define BITS_COPY32_PTR(a,bits) \
+{ \
+   BIT128_CLEAR_ALL_PTR(a); \
+   BITS_GET_ELEM_PTR(a, 0) = (bits); \
+}
+
+#define BITS_COPY64_PTR(a,bits) \
+{ \
+   BIT128_CLEAR_ALL_PTR(a); \
+   BITS_GET_ELEM_PTR(a, 0) = (bits); \
+   BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \
+}
+
+/* Helper macros and struct to keep track of many booleans. */
+/* This struct has 256 bits. */
+typedef struct
+{
+   uint32_t data[8];
+} retro_bits_t;
+
+/* This struct has 512 bits. */
+typedef struct
+{
+   uint32_t data[16];
+} retro_bits_512_t;
+
+#ifdef _WIN32
+#  ifdef _WIN64
+#    define PRI_SIZET PRIu64
+#  else
+#    if _MSC_VER == 1800
+#      define PRI_SIZET PRIu32
+#    else
+#      define PRI_SIZET "u"
+#    endif
+#  endif
+#elif defined(PS2)
+#  define PRI_SIZET "u"
+#else
+#  if (SIZE_MAX == 0xFFFF)
+#    define PRI_SIZET "hu"
+#  elif (SIZE_MAX == 0xFFFFFFFF)
+#    define PRI_SIZET "u"
+#  elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
+#    define PRI_SIZET "lu"
+#  else
+#    error PRI_SIZET: unknown SIZE_MAX
+#  endif
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/retro_stat.h b/deps/libretro-common/include/retro_stat.h
new file mode 100644 (file)
index 0000000..a6d53ab
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright  (C) 2010-2016 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_stat.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __RETRO_STAT_H
+#define __RETRO_STAT_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+/**
+ * path_is_directory:
+ * @path               : path
+ *
+ * Checks if path is a directory.
+ *
+ * Returns: true (1) if path is a directory, otherwise false (0).
+ */
+bool path_is_directory(const char *path);
+
+bool path_is_character_special(const char *path);
+
+bool path_is_valid(const char *path);
+
+int32_t path_get_size(const char *path);
+
+/**
+ * path_mkdir_norecurse:
+ * @dir                : directory
+ *
+ * Create directory on filesystem.
+ *
+ * Returns: true (1) if directory could be created, otherwise false (0).
+ **/
+bool mkdir_norecurse(const char *dir);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/retro_timers.h b/deps/libretro-common/include/retro_timers.h
new file mode 100644 (file)
index 0000000..04a860a
--- /dev/null
@@ -0,0 +1,112 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_timers.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_COMMON_TIMERS_H
+#define __LIBRETRO_COMMON_TIMERS_H
+
+#include <stdint.h>
+
+#if defined(XENON)
+#include <time/time.h>
+#elif !defined(__PSL1GHT__) && defined(__PS3__)
+#include <sys/timer.h>
+#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
+#include <unistd.h>
+#elif defined(WIIU)
+#include <wiiu/os/thread.h>
+#elif defined(PSP)
+#include <pspthreadman.h>
+#elif defined(VITA)
+#include <psp2/kernel/threadmgr.h>
+#elif defined(_3DS)
+#include <3ds.h>
+#else
+#include <time.h>
+#endif
+
+#if defined(_WIN32) && !defined(_XBOX)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#elif defined(_WIN32) && defined(_XBOX)
+#include <Xtl.h>
+#endif
+
+#include <limits.h>
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+#include <retro_inline.h>
+
+#ifdef DJGPP
+#define timespec timeval
+#define tv_nsec tv_usec
+#include <unistd.h>
+
+extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+
+static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
+{
+   usleep(1000000L * rqtp->tv_sec + rqtp->tv_nsec / 1000);
+
+   if (rmtp)
+      rmtp->tv_sec = rmtp->tv_nsec=0;
+
+   return 0;
+}
+
+#define nanosleep nanosleepDOS
+#endif
+
+/**
+ * retro_sleep:
+ * @msec         : amount in milliseconds to sleep
+ *
+ * Sleeps for a specified amount of milliseconds (@msec).
+ **/
+#if defined(VITA)
+#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))
+#elif defined(_3DS)
+#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))
+#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+#define retro_sleep(msec) (SleepEx((msec), FALSE))
+#elif defined(_WIN32)
+#define retro_sleep(msec) (Sleep((msec)))
+#elif defined(XENON)
+#define retro_sleep(msec) (udelay(1000 * (msec)))
+#elif !defined(__PSL1GHT__) && defined(__PS3__)
+#define retro_sleep(msec) (sys_timer_usleep(1000 * (msec)))
+#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
+#define retro_sleep(msec) (usleep(1000 * (msec)))
+#elif defined(WIIU)
+#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
+#else
+static INLINE void retro_sleep(unsigned msec)
+{
+   struct timespec tv;
+   tv.tv_sec          = msec / 1000;
+   tv.tv_nsec         = (msec % 1000) * 1000000;
+   nanosleep(&tv, NULL);
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/include/rthreads/async_job.h b/deps/libretro-common/include/rthreads/async_job.h
new file mode 100644 (file)
index 0000000..aa081d7
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (async_job.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_ASYNC_JOB_H
+#define __LIBRETRO_SDK_ASYNC_JOB_H
+
+typedef struct async_job async_job_t;
+typedef void (*async_task_t)(void *payload);
+
+async_job_t *async_job_new(void);
+
+void async_job_free(async_job_t *ajob);
+
+int async_job_add(async_job_t *ajob, async_task_t task, void *payload);
+
+#endif /* __LIBRETRO_SDK_ASYNC_JOB_H */
diff --git a/deps/libretro-common/include/rthreads/rthreads.h b/deps/libretro-common/include/rthreads/rthreads.h
new file mode 100644 (file)
index 0000000..e4460a1
--- /dev/null
@@ -0,0 +1,269 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rthreads.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_RTHREADS_H__
+#define __LIBRETRO_SDK_RTHREADS_H__
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+#include <stdint.h>
+#include <retro_inline.h>
+#include <retro_miscellaneous.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct sthread sthread_t;
+typedef struct slock slock_t;
+typedef struct scond scond_t;
+
+#ifdef HAVE_THREAD_STORAGE
+typedef unsigned sthread_tls_t;
+#endif
+
+/**
+ * sthread_create:
+ * @start_routine           : thread entry callback function
+ * @userdata                : pointer to userdata that will be made
+ *                            available in thread entry callback function
+ *
+ * Create a new thread.
+ *
+ * Returns: pointer to new thread if successful, otherwise NULL.
+ */
+sthread_t *sthread_create(void (*thread_func)(void*), void *userdata);
+
+/**
+ * sthread_create_with_priority:
+ * @start_routine           : thread entry callback function
+ * @userdata                : pointer to userdata that will be made
+ *                            available in thread entry callback function
+ * @thread_priority         : thread priority hint value from [1-100]
+ *
+ * Create a new thread. It is possible for the caller to give a hint
+ * for the thread's priority from [1-100]. Any passed in @thread_priority
+ * values that are outside of this range will cause sthread_create() to
+ * create a new thread using the operating system's default thread
+ * priority.
+ *
+ * Returns: pointer to new thread if successful, otherwise NULL.
+ */
+sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority);
+
+/**
+ * sthread_detach:
+ * @thread                  : pointer to thread object
+ *
+ * Detach a thread. When a detached thread terminates, its
+ * resource sare automatically released back to the system
+ * without the need for another thread to join with the
+ * terminated thread.
+ *
+ * Returns: 0 on success, otherwise it returns a non-zero error number.
+ */
+int sthread_detach(sthread_t *thread);
+
+/**
+ * sthread_join:
+ * @thread                  : pointer to thread object
+ *
+ * Join with a terminated thread. Waits for the thread specified by
+ * @thread to terminate. If that thread has already terminated, then
+ * it will return immediately. The thread specified by @thread must
+ * be joinable.
+ *
+ * Returns: 0 on success, otherwise it returns a non-zero error number.
+ */
+void sthread_join(sthread_t *thread);
+
+/**
+ * sthread_isself:
+ * @thread                  : pointer to thread object
+ *
+ * Returns: true (1) if calling thread is the specified thread
+ */
+bool sthread_isself(sthread_t *thread);
+
+/**
+ * slock_new:
+ *
+ * Create and initialize a new mutex. Must be manually
+ * freed.
+ *
+ * Returns: pointer to a new mutex if successful, otherwise NULL.
+ **/
+slock_t *slock_new(void);
+
+/**
+ * slock_free:
+ * @lock                    : pointer to mutex object
+ *
+ * Frees a mutex.
+ **/
+void slock_free(slock_t *lock);
+
+/**
+ * slock_lock:
+ * @lock                    : pointer to mutex object
+ *
+ * Locks a mutex. If a mutex is already locked by
+ * another thread, the calling thread shall block until
+ * the mutex becomes available.
+**/
+void slock_lock(slock_t *lock);
+
+/**
+ * slock_try_lock:
+ * @lock                    : pointer to mutex object
+ *
+ * Attempts to lock a mutex. If a mutex is already locked by
+ * another thread, return false.  If the lock is acquired, return true.
+**/
+bool slock_try_lock(slock_t *lock);
+
+/**
+ * slock_unlock:
+ * @lock                    : pointer to mutex object
+ *
+ * Unlocks a mutex.
+ **/
+void slock_unlock(slock_t *lock);
+
+/**
+ * scond_new:
+ *
+ * Creates and initializes a condition variable. Must
+ * be manually freed.
+ *
+ * Returns: pointer to new condition variable on success,
+ * otherwise NULL.
+ **/
+scond_t *scond_new(void);
+
+/**
+ * scond_free:
+ * @cond                    : pointer to condition variable object
+ *
+ * Frees a condition variable.
+**/
+void scond_free(scond_t *cond);
+
+/**
+ * scond_wait:
+ * @cond                    : pointer to condition variable object
+ * @lock                    : pointer to mutex object
+ *
+ * Block on a condition variable (i.e. wait on a condition).
+ **/
+void scond_wait(scond_t *cond, slock_t *lock);
+
+/**
+ * scond_wait_timeout:
+ * @cond                    : pointer to condition variable object
+ * @lock                    : pointer to mutex object
+ * @timeout_us              : timeout (in microseconds)
+ *
+ * Try to block on a condition variable (i.e. wait on a condition) until
+ * @timeout_us elapses.
+ *
+ * Returns: false (0) if timeout elapses before condition variable is
+ * signaled or broadcast, otherwise true (1).
+ **/
+bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);
+
+/**
+ * scond_broadcast:
+ * @cond                    : pointer to condition variable object
+ *
+ * Broadcast a condition. Unblocks all threads currently blocked
+ * on the specified condition variable @cond.
+ **/
+int scond_broadcast(scond_t *cond);
+
+/**
+ * scond_signal:
+ * @cond                    : pointer to condition variable object
+ *
+ * Signal a condition. Unblocks at least one of the threads currently blocked
+ * on the specified condition variable @cond.
+ **/
+void scond_signal(scond_t *cond);
+
+#ifdef HAVE_THREAD_STORAGE
+/**
+ * @brief Creates a thread local storage key
+ *
+ * This function shall create thread-specific data key visible to all threads in
+ * the process. The same key can be used by multiple threads to store
+ * thread-local data.
+ *
+ * When the key is created NULL shall be associated with it in all active
+ * threads. Whenever a new thread is spawned the all defined keys will be
+ * associated with NULL on that thread.
+ *
+ * @param tls
+ * @return whether the operation suceeded or not
+ */
+bool sthread_tls_create(sthread_tls_t *tls);
+
+/**
+ * @brief Deletes a thread local storage
+ * @param tls
+ * @return whether the operation suceeded or not
+ */
+bool sthread_tls_delete(sthread_tls_t *tls);
+
+/**
+ * @brief Retrieves thread specific data associated with a key
+ *
+ * There is no way to tell whether this function failed.
+ *
+ * @param tls
+ * @return
+ */
+void *sthread_tls_get(sthread_tls_t *tls);
+
+/**
+ * @brief Binds thread specific data to a key
+ * @param tls
+ * @return Whether the operation suceeded or not
+ */
+bool sthread_tls_set(sthread_tls_t *tls, const void *data);
+#endif
+
+/*
+ * @brief Get thread ID of specified thread
+ * @param thread
+ * @return The ID of the specified thread
+ */
+uintptr_t sthread_get_thread_id(sthread_t *thread);
+
+/*
+ * @brief Get thread ID of the current thread
+ * @param 
+ * @return The ID of the current thread
+ */
+uintptr_t sthread_get_current_thread_id(void);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/rthreads/tpool.h b/deps/libretro-common/include/rthreads/tpool.h
new file mode 100644 (file)
index 0000000..6f60f37
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010-2020 The RetroArch team
+ * Copyright (c) 2017 John Schember <john@nachtimwald.com>
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (tpool.h).
+ * ---------------------------------------------------------------------------------------
+ * 
+ * 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 __LIBRETRO_SDK_TPOOL_H__
+#define __LIBRETRO_SDK_TPOOL_H__
+
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+#include <retro_inline.h>
+#include <retro_miscellaneous.h>
+
+RETRO_BEGIN_DECLS
+
+struct tpool;
+typedef struct tpool tpool_t;
+
+/** 
+ * (*thread_func_t):
+ * @arg           : Argument.
+ * 
+ * Callback function that the pool will call to do work.
+ **/
+typedef void (*thread_func_t)(void *arg);
+
+/**
+ * tpool_create:
+ * @num           : Number of threads the pool should have.
+ *                  If 0 defaults to 2.
+ *
+ * Create a thread pool.
+ * 
+ * Returns: pool.
+ */
+tpool_t *tpool_create(size_t num);
+
+/** 
+ * tpool_destroy:
+ * @tp            : Thread pool.
+ * 
+ * Destory a thread pool
+ * The pool can be destroyed while there is outstanding work to process. All
+ * outstanding unprocessed work will be discareded. There may be a delay before
+ * this function returns because it will block for work that is processing to
+ * complete.
+ **/
+void tpool_destroy(tpool_t *tp);
+
+/** 
+ * tpool_add_work:
+ * @tp         : Thread pool.
+ * @func       : Function the pool should call.
+ * @arg        : Argument to pass to func.
+ * 
+ * Add work to a thread pool.
+ *
+ * Returns: true if work was added, otherwise false.
+ **/
+bool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg);
+
+/**
+ * tpool_wait:
+ * @tp Thread pool.
+ * 
+ * Wait for all work in the pool to be completed.
+ */
+void tpool_wait(tpool_t *tp);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/chd_stream.h b/deps/libretro-common/include/streams/chd_stream.h
new file mode 100644 (file)
index 0000000..51fd4d3
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (chd_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_FILE_CHD_STREAM_H
+#define _LIBRETRO_SDK_FILE_CHD_STREAM_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct chdstream chdstream_t;
+
+/* First data track */
+#define CHDSTREAM_TRACK_FIRST_DATA (-1)
+/* Last track */
+#define CHDSTREAM_TRACK_LAST (-2)
+/* Primary (largest) data track, used for CRC identification purposes */
+#define CHDSTREAM_TRACK_PRIMARY (-3)
+
+chdstream_t *chdstream_open(const char *path, int32_t track);
+
+void chdstream_close(chdstream_t *stream);
+
+ssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes);
+
+int chdstream_getc(chdstream_t *stream);
+
+char *chdstream_gets(chdstream_t *stream, char *buffer, size_t len);
+
+uint64_t chdstream_tell(chdstream_t *stream);
+
+void chdstream_rewind(chdstream_t *stream);
+
+int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence);
+
+ssize_t chdstream_get_size(chdstream_t *stream);
+
+uint32_t chdstream_get_track_start(chdstream_t* stream);
+
+uint32_t chdstream_get_frame_size(chdstream_t* stream);
+
+uint32_t chdstream_get_first_track_sector(chdstream_t* stream);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/file_stream.h b/deps/libretro-common/include/streams/file_stream.h
new file mode 100644 (file)
index 0000000..079221e
--- /dev/null
@@ -0,0 +1,142 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_FILE_STREAM_H
+#define __LIBRETRO_SDK_FILE_STREAM_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <sys/types.h>
+
+#include <libretro.h>
+#include <retro_common_api.h>
+#include <retro_inline.h>
+#include <boolean.h>
+
+#include <stdarg.h>
+#include <vfs/vfs_implementation.h>
+
+#define FILESTREAM_REQUIRED_VFS_VERSION 2
+
+RETRO_BEGIN_DECLS
+
+typedef struct RFILE RFILE;
+
+#define FILESTREAM_REQUIRED_VFS_VERSION 2
+
+void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
+
+int64_t filestream_get_size(RFILE *stream);
+
+int64_t filestream_truncate(RFILE *stream, int64_t length);
+
+/**
+ * filestream_open:
+ * @path               : path to file
+ * @mode               : file mode to use when opening (read/write)
+ * @bufsize            : optional buffer size (-1 or 0 to use default)
+ *
+ * Opens a file for reading or writing, depending on the requested mode.
+ * @return A pointer to an RFILE if opened successfully, otherwise NULL.
+ **/
+RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
+
+int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
+
+int64_t filestream_read(RFILE *stream, void *data, int64_t len);
+
+int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
+
+int64_t filestream_tell(RFILE *stream);
+
+void filestream_rewind(RFILE *stream);
+
+int filestream_close(RFILE *stream);
+
+/**
+ * filestream_read_file:
+ * @path             : path to file.
+ * @buf              : buffer to allocate and read the contents of the
+ *                     file into. Needs to be freed manually.
+ * @len              : optional output integer containing bytes read.
+ *
+ * Read the contents of a file into @buf.
+ *
+ * @return Non-zero on success.
+ */
+int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
+
+char* filestream_gets(RFILE *stream, char *s, size_t len);
+
+int filestream_getc(RFILE *stream);
+
+int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
+
+int filestream_scanf(RFILE *stream, const char* format, ...);
+
+int filestream_eof(RFILE *stream);
+
+/**
+ * filestream_write_file:
+ * @path             : path to file.
+ * @data             : contents to write to the file.
+ * @size             : size of the contents.
+ *
+ * Writes data to a file.
+ *
+ * @return true on success, otherwise false.
+ **/
+bool filestream_write_file(const char *path, const void *data, int64_t size);
+
+int filestream_putc(RFILE *stream, int c);
+
+int filestream_vprintf(RFILE *stream, const char* format, va_list args);
+
+int filestream_printf(RFILE *stream, const char* format, ...);
+
+int filestream_error(RFILE *stream);
+
+int filestream_flush(RFILE *stream);
+
+int filestream_delete(const char *path);
+
+int filestream_rename(const char *old_path, const char *new_path);
+
+const char* filestream_get_path(RFILE *stream);
+
+bool filestream_exists(const char *path);
+
+/**
+ * filestream_getline:
+ *
+ * Returned pointer must be freed by the caller.
+ **/
+char* filestream_getline(RFILE *stream);
+
+libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/file_stream_transforms.h b/deps/libretro-common/include/streams/file_stream_transforms.h
new file mode 100644 (file)
index 0000000..327e218
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (file_stream_transforms.h).
+* ---------------------------------------------------------------------------------------
+*
+* 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 __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
+#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
+
+#include <stdint.h>
+#include <string.h>
+#include <retro_common_api.h>
+#include <streams/file_stream.h>
+
+RETRO_BEGIN_DECLS
+
+#ifndef SKIP_STDIO_REDEFINES
+
+#define FILE RFILE
+
+#undef fopen
+#undef fclose
+#undef ftell
+#undef fseek
+#undef fread
+#undef fgets
+#undef fgetc
+#undef fwrite
+#undef fputc
+#undef fflush
+#undef fprintf
+#undef ferror
+#undef feof
+#undef fscanf
+
+#define fopen rfopen
+#define fclose rfclose
+#define ftell rftell
+#define fseek rfseek
+#define fread rfread
+#define fgets rfgets
+#define fgetc rfgetc
+#define fwrite rfwrite
+#define fputc rfputc
+#define fflush rfflush
+#define fprintf rfprintf
+#define ferror rferror
+#define feof rfeof
+#define fscanf rfscanf
+
+#endif
+
+RFILE* rfopen(const char *path, const char *mode);
+
+int rfclose(RFILE* stream);
+
+int64_t rftell(RFILE* stream);
+
+int64_t rfseek(RFILE* stream, int64_t offset, int origin);
+
+int64_t rfread(void* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream);
+
+char *rfgets(char *buffer, int maxCount, RFILE* stream);
+
+int rfgetc(RFILE* stream);
+
+int64_t rfwrite(void const* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream);
+
+int rfputc(int character, RFILE * stream);
+
+int64_t rfflush(RFILE * stream);
+
+int rfprintf(RFILE * stream, const char * format, ...);
+
+int rferror(RFILE* stream);
+
+int rfeof(RFILE* stream);
+
+int rfscanf(RFILE * stream, const char * format, ...);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/interface_stream.h b/deps/libretro-common/include/streams/interface_stream.h
new file mode 100644 (file)
index 0000000..b62552f
--- /dev/null
@@ -0,0 +1,132 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (interface_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_INTERFACE_STREAM_H
+#define _LIBRETRO_SDK_INTERFACE_STREAM_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <retro_common_api.h>
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+enum intfstream_type
+{
+   INTFSTREAM_FILE = 0,
+   INTFSTREAM_MEMORY,
+   INTFSTREAM_CHD,
+   INTFSTREAM_RZIP
+};
+
+typedef struct intfstream_internal intfstream_internal_t, intfstream_t;
+
+typedef struct intfstream_info
+{
+   struct
+   {
+      struct
+      {
+         uint8_t *data;
+         uint64_t size;
+      } buf;
+      bool writable;
+   } memory;
+   struct
+   {
+      void *handle;
+      int32_t track;
+   } chd;
+   enum intfstream_type type;
+} intfstream_info_t;
+
+void *intfstream_init(intfstream_info_t *info);
+
+bool intfstream_resize(intfstream_internal_t *intf,
+      intfstream_info_t *info);
+
+bool intfstream_open(intfstream_internal_t *intf,
+      const char *path, unsigned mode, unsigned hints);
+
+int64_t intfstream_read(intfstream_internal_t *intf,
+      void *s, uint64_t len);
+
+int64_t intfstream_write(intfstream_internal_t *intf,
+      const void *s, uint64_t len);
+
+int intfstream_printf(intfstream_internal_t *intf,
+      const char* format, ...);
+
+int64_t intfstream_get_ptr(intfstream_internal_t *intf);
+
+char *intfstream_gets(intfstream_internal_t *intf,
+      char *buffer, uint64_t len);
+
+int intfstream_getc(intfstream_internal_t *intf);
+
+int64_t intfstream_seek(intfstream_internal_t *intf,
+      int64_t offset, int whence);
+
+void intfstream_rewind(intfstream_internal_t *intf);
+
+int64_t intfstream_tell(intfstream_internal_t *intf);
+
+int intfstream_eof(intfstream_internal_t *intf);
+
+void intfstream_putc(intfstream_internal_t *intf, int c);
+
+int intfstream_close(intfstream_internal_t *intf);
+
+int64_t intfstream_get_size(intfstream_internal_t *intf);
+
+int intfstream_flush(intfstream_internal_t *intf);
+
+uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf);
+
+uint32_t intfstream_get_frame_size(intfstream_internal_t *intf);
+
+uint32_t intfstream_get_first_sector(intfstream_internal_t* intf);
+
+bool intfstream_is_compressed(intfstream_internal_t *intf);
+
+bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc);
+
+intfstream_t *intfstream_open_file(const char *path,
+      unsigned mode, unsigned hints);
+
+intfstream_t *intfstream_open_memory(void *data,
+      unsigned mode, unsigned hints, uint64_t size);
+
+intfstream_t *intfstream_open_writable_memory(void *data,
+      unsigned mode, unsigned hints, uint64_t size);
+
+intfstream_t *intfstream_open_chd_track(const char *path,
+      unsigned mode, unsigned hints, int32_t track);
+
+intfstream_t *intfstream_open_rzip_file(const char *path,
+      unsigned mode);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/memory_stream.h b/deps/libretro-common/include/streams/memory_stream.h
new file mode 100644 (file)
index 0000000..2c6f3fc
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (memory_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_FILE_MEMORY_STREAM_H
+#define _LIBRETRO_SDK_FILE_MEMORY_STREAM_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+typedef struct memstream memstream_t;
+
+memstream_t *memstream_open(unsigned writing);
+
+void memstream_close(memstream_t *stream);
+
+uint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes);
+
+uint64_t memstream_write(memstream_t *stream, const void *data, uint64_t bytes);
+
+int memstream_getc(memstream_t *stream);
+
+void memstream_putc(memstream_t *stream, int c);
+
+char *memstream_gets(memstream_t *stream, char *buffer, size_t len);
+
+uint64_t memstream_pos(memstream_t *stream);
+
+void memstream_rewind(memstream_t *stream);
+
+int64_t memstream_seek(memstream_t *stream, int64_t offset, int whence);
+
+void memstream_set_buffer(uint8_t *buffer, uint64_t size);
+
+uint64_t memstream_get_last_size(void);
+
+uint64_t memstream_get_ptr(memstream_t *stream);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/network_stream.h b/deps/libretro-common/include/streams/network_stream.h
new file mode 100644 (file)
index 0000000..36aa40b
--- /dev/null
@@ -0,0 +1,267 @@
+/* Copyright  (C) 2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (network_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_NETWORK_STREAM_H
+#define _LIBRETRO_SDK_NETWORK_STREAM_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <boolean.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+enum
+{
+   NETSTREAM_SEEK_SET = 0,
+   NETSTREAM_SEEK_CUR,
+   NETSTREAM_SEEK_END
+};
+
+typedef struct netstream
+{
+   void   *buf;
+   size_t size;
+   size_t used;
+   size_t pos;
+} netstream_t;
+
+/**
+ * netstream_open:
+ *
+ * @stream : Pointer to a network stream object.
+ * @buf    : Pre-allocated buffer. Pass NULL to dynamically allocate a buffer.
+ * @size   : Buffer size. Pass 0 for no pre-allocated/initial buffer.
+ * @used   : Buffer bytes in use. Ignored for non pre-allocated buffers.
+ *
+ * Opens a network stream.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_open(netstream_t *stream, void *buf, size_t size, size_t used);
+
+/**
+ * netstream_close:
+ *
+ * @stream  : Pointer to a network stream object.
+ * @dealloc : Whether to deallocate/free the buffer or not.
+ *
+ * Closes a network stream.
+ *
+ */
+void netstream_close(netstream_t *stream, bool dealloc);
+
+/**
+ * netstream_reset:
+ *
+ * @stream : Pointer to a network stream object.
+ *
+ * Resets a network stream to its initial position,
+ * discarding any used bytes in the process.
+ *
+ */
+void netstream_reset(netstream_t *stream);
+
+/**
+ * netstream_truncate:
+ *
+ * @stream : Pointer to a network stream object.
+ * @used   : Amount of bytes used.
+ *
+ * Truncates the network stream.
+ * Truncation can either extend or reduce the amount of bytes used.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_truncate(netstream_t *stream, size_t used);
+
+/**
+ * netstream_data:
+ *
+ * @stream : Pointer to a network stream object.
+ * @data   : Pointer to an object to store a reference of the stream's data.
+ * @len    : Pointer to an object to store the amount of bytes in use.
+ *
+ * Gets the network stream's data.
+ *
+ */
+void netstream_data(netstream_t *stream, void **data, size_t *len);
+
+/**
+ * netstream_eof:
+ *
+ * @stream : Pointer to a network stream object.
+ *
+ * Checks whether the network stream is at EOF or not.
+ *
+ * Returns: true if the stream is at EOF, false otherwise.
+ */
+bool netstream_eof(netstream_t *stream);
+
+/**
+ * netstream_tell:
+ *
+ * @stream : Pointer to a network stream object.
+ *
+ * Gets the network stream's current position.
+ *
+ * Returns: current value of the position indicator.
+ */
+size_t netstream_tell(netstream_t *stream);
+
+/**
+ * netstream_seek:
+ *
+ * @stream : Pointer to a network stream object.
+ * @offset : Position's offset.
+ * @origin : Position used as reference for the offset.
+ *
+ * Sets the network stream's current position.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_seek(netstream_t *stream, long offset, int origin);
+
+/**
+ * netstream_read:
+ *
+ * @stream : Pointer to a network stream object.
+ * @data   : Pointer to a storage for data read from the network stream.
+ * @len    : Amount of bytes to read. Pass 0 to read all remaining bytes.
+ *
+ * Reads raw data from the network stream.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_read(netstream_t *stream, void *data, size_t len);
+
+/**
+ * netstream_read_(type):
+ *
+ * @stream : Pointer to a network stream object.
+ * @data   : Pointer to a storage for data read from the network stream.
+ *
+ * Reads data from the network stream.
+ * Network byte order is always big endian.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_read_byte(netstream_t   *stream, uint8_t  *data);
+bool netstream_read_word(netstream_t   *stream, uint16_t *data);
+bool netstream_read_dword(netstream_t  *stream, uint32_t *data);
+bool netstream_read_qword(netstream_t  *stream, uint64_t *data);
+#ifdef __STDC_IEC_559__
+bool netstream_read_float(netstream_t  *stream, float    *data);
+bool netstream_read_double(netstream_t *stream, double   *data);
+#endif
+
+/**
+ * netstream_read_string:
+ *
+ * @stream : Pointer to a network stream object.
+ * @s      : Pointer to a string buffer.
+ * @len    : Size of the string buffer.
+ *
+ * Reads a string from the network stream.
+ *
+ * Returns: Length of the original string on success or
+ * a negative value on error.
+ */
+int netstream_read_string(netstream_t *stream, char *s, size_t len);
+
+/**
+ * netstream_read_fixed_string:
+ *
+ * @stream : Pointer to a network stream object.
+ * @s      : Pointer to a string buffer.
+ * @len    : Size of the string buffer.
+ *
+ * Reads a fixed-length string from the network stream.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len);
+
+/**
+ * netstream_write:
+ *
+ * @stream : Pointer to a network stream object.
+ * @data   : Data to write into the network stream.
+ * @len    : Amount of bytes to write.
+ *
+ * Writes raw data into the network stream.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_write(netstream_t *stream, const void *data, size_t len);
+
+/**
+ * netstream_write_(type):
+ *
+ * @stream : Pointer to a network stream object.
+ * @data   : Data to write into the network stream.
+ *
+ * Writes data into the network stream.
+ * Network byte order is always big endian.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_write_byte(netstream_t   *stream, uint8_t  data);
+bool netstream_write_word(netstream_t   *stream, uint16_t data);
+bool netstream_write_dword(netstream_t  *stream, uint32_t data);
+bool netstream_write_qword(netstream_t  *stream, uint64_t data);
+#ifdef __STDC_IEC_559__
+bool netstream_write_float(netstream_t  *stream, float    data);
+bool netstream_write_double(netstream_t *stream, double   data);
+#endif
+
+/**
+ * netstream_write_string:
+ *
+ * @stream : Pointer to a network stream object.
+ * @s      : Pointer to a string.
+ *
+ * Writes a null-terminated string into the network stream.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_write_string(netstream_t *stream, const char *s);
+
+/**
+ * netstream_write_fixed_string:
+ *
+ * @stream : Pointer to a network stream object.
+ * @s      : Pointer to a string.
+ * @len    : Size of the string.
+ *
+ * Writes a null-terminated fixed-length string into the network stream.
+ *
+ * Returns: true on success, false otherwise.
+ */
+bool netstream_write_fixed_string(netstream_t *stream, const char *s,
+      size_t len);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/rzip_stream.h b/deps/libretro-common/include/streams/rzip_stream.h
new file mode 100644 (file)
index 0000000..0dcc7f2
--- /dev/null
@@ -0,0 +1,188 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rzip_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _LIBRETRO_SDK_FILE_RZIP_STREAM_H
+#define _LIBRETRO_SDK_FILE_RZIP_STREAM_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/* Rudimentary interface for streaming data to/from a
+ * zlib-compressed chunk-based RZIP archive file.
+ * 
+ * This is somewhat less efficient than using regular
+ * gzip code, but this is by design - the intention here
+ * is to create an interface that integrates seamlessly
+ * with normal RetroArch functionality, using only
+ * standard/existing libretro-common routines.
+ * (Actual efficiency is pretty good, regardless:
+ * archived file size is almost identical to a solid
+ * zip file, and compression/decompression speed is
+ * not substantially worse than external archiving tools;
+ * it is certainly acceptable for use in real-time
+ * frontend applications)
+ * 
+ * When reading existing files, uncompressed content
+ * is handled automatically. File type (compressed/
+ * uncompressed) is detected via the RZIP header.
+ * 
+ * ## RZIP file format:
+ * 
+ * <file id header>:                8 bytes
+ *                                  - [#][R][Z][I][P][v][file format version][#]
+ * <uncompressed chunk size>:       4 bytes, little endian order
+ *                                  - nominal (maximum) size of each uncompressed
+ *                                    chunk, in bytes
+ * <total uncompressed data size>:  8 bytes, little endian order
+ * <size of next compressed chunk>: 4 bytes, little endian order
+ *                                  - size on-disk of next compressed data
+ *                                    chunk, in bytes
+ * <next compressed chunk>:         n bytes of zlib compressed data
+ * ...
+ * <size of next compressed chunk> : repeated until end of file
+ * <next compressed chunk>         :
+ * 
+ */
+
+/* Prevent direct access to rzipstream_t members */
+typedef struct rzipstream rzipstream_t;
+
+/* File Open */
+
+/* Opens a new or existing RZIP file
+ * > Supported 'mode' values are:
+ *   - RETRO_VFS_FILE_ACCESS_READ
+ *   - RETRO_VFS_FILE_ACCESS_WRITE
+ * > When reading, 'path' may reference compressed
+ *   or uncompressed data
+ * Returns NULL if arguments are invalid, file
+ * is invalid or an IO error occurs */
+rzipstream_t* rzipstream_open(const char *path, unsigned mode);
+
+/* File Read */
+
+/* Reads (a maximum of) 'len' bytes from an RZIP file.
+ * Returns actual number of bytes read, or -1 in
+ * the event of an error */
+int64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len);
+
+/* Reads next character from an RZIP file.
+ * Returns character value, or EOF if no data
+ * remains.
+ * Note: Always returns EOF if file is open
+ * for writing. */
+int rzipstream_getc(rzipstream_t *stream);
+
+/* Reads one line from an RZIP file and stores it
+ * in the character array pointed to by 's'.
+ * It stops reading when either (len-1) characters
+ * are read, the newline character is read, or the
+ * end-of-file is reached, whichever comes first.
+ * On success, returns 's'. In the event of an error,
+ * or if end-of-file is reached and no characters
+ * have been read, returns NULL. */
+char* rzipstream_gets(rzipstream_t *stream, char *s, size_t len);
+
+/* Reads all data from file specified by 'path' and
+ * copies it to 'buf'.
+ * - 'buf' will be allocated and must be free()'d manually.
+ * - Allocated 'buf' size is equal to 'len'.
+ * Returns false in the event of an error */
+bool rzipstream_read_file(const char *path, void **buf, int64_t *len);
+
+/* File Write */
+
+/* Writes 'len' bytes to an RZIP file.
+ * Returns actual number of bytes written, or -1
+ * in the event of an error */
+int64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len);
+
+/* Writes a single character to an RZIP file.
+ * Returns character written, or EOF in the event
+ * of an error */
+int rzipstream_putc(rzipstream_t *stream, int c);
+
+/* Writes a variable argument list to an RZIP file.
+ * Ugly 'internal' function, required to enable
+ * 'printf' support in the higher level 'interface_stream'.
+ * Returns actual number of bytes written, or -1
+ * in the event of an error */
+int rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args);
+
+/* Writes formatted output to an RZIP file.
+ * Returns actual number of bytes written, or -1
+ * in the event of an error */
+int rzipstream_printf(rzipstream_t *stream, const char* format, ...);
+
+/* Writes contents of 'data' buffer to file
+ * specified by 'path'.
+ * Returns false in the event of an error */
+bool rzipstream_write_file(const char *path, const void *data, int64_t len);
+
+/* File Control */
+
+/* Sets file position to the beginning of the
+ * specified RZIP file.
+ * Note: It is not recommended to rewind a file
+ * that is open for writing, since the caller
+ * may end up with a file containing junk data
+ * at the end (harmless, but a waste of space). */
+void rzipstream_rewind(rzipstream_t *stream);
+
+/* File Status */
+
+/* Returns total size (in bytes) of the *uncompressed*
+ * data in an RZIP file.
+ * (If reading an uncompressed file, this corresponds
+ * to the 'physical' file size in bytes)
+ * Returns -1 in the event of a error. */
+int64_t rzipstream_get_size(rzipstream_t *stream);
+
+/* Returns EOF when no further *uncompressed* data
+ * can be read from an RZIP file. */
+int rzipstream_eof(rzipstream_t *stream);
+
+/* Returns the offset of the current byte of *uncompressed*
+ * data relative to the beginning of an RZIP file.
+ * Returns -1 in the event of a error. */
+int64_t rzipstream_tell(rzipstream_t *stream);
+
+/* Returns true if specified RZIP file contains
+ * compressed content */
+bool rzipstream_is_compressed(rzipstream_t *stream);
+
+/* File Close */
+
+/* Closes RZIP file. If file is open for writing,
+ * flushes any remaining buffered data to disk.
+ * Returns -1 in the event of a error. */
+int rzipstream_close(rzipstream_t *stream);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/stdin_stream.h b/deps/libretro-common/include/streams/stdin_stream.h
new file mode 100644 (file)
index 0000000..4dd3546
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (stdin_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_SDK_STDIN_STREAM_H__
+#define LIBRETRO_SDK_STDIN_STREAM_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <retro_miscellaneous.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+size_t read_stdin(char *buf, size_t size);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/streams/trans_stream.h b/deps/libretro-common/include/streams/trans_stream.h
new file mode 100644 (file)
index 0000000..79c0570
--- /dev/null
@@ -0,0 +1,106 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (trans_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 LIBRETRO_SDK_TRANS_STREAM_H__
+#define LIBRETRO_SDK_TRANS_STREAM_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <boolean.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <retro_miscellaneous.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+enum trans_stream_error
+{
+    TRANS_STREAM_ERROR_NONE = 0,
+    TRANS_STREAM_ERROR_AGAIN, /* more work to do */
+    TRANS_STREAM_ERROR_ALLOCATION_FAILURE, /* malloc failure */
+    TRANS_STREAM_ERROR_INVALID, /* invalid state */
+    TRANS_STREAM_ERROR_BUFFER_FULL, /* output buffer full */
+    TRANS_STREAM_ERROR_OTHER
+};
+
+struct trans_stream_backend
+{
+   const char *ident;
+   const struct trans_stream_backend *reverse;
+
+   /* Create a stream data structure */
+   void *(*stream_new)(void);
+
+   /* Free it */
+   void  (*stream_free)(void *);
+
+   /* (Optional) Set extra properties, defined per transcoder */
+   bool  (*define)(void *, const char *, uint32_t);
+
+   /* Set our input source */
+   void  (*set_in)(void *, const uint8_t *, uint32_t);
+
+   /* Set our output target */
+   void  (*set_out)(void *, uint8_t *, uint32_t);
+
+   /* Perform a transcoding, flushing/finalizing if asked to. Writes out how
+    * many bytes were read and written. Error target optional. */
+   bool  (*trans)(void *, bool, uint32_t *, uint32_t *, enum trans_stream_error *);
+};
+
+/**
+ * trans_stream_trans_full:
+ * @backend                     : transcoding backend
+ * @data                        : (optional) existing stream data, or a target
+ *                                for the new stream data to be saved
+ * @in                          : input data
+ * @in_size                     : input size
+ * @out                         : output data
+ * @out_size                    : output size
+ * @error                       : (optional) output for error code
+ *
+ * Perform a full transcoding from a source to a destination.
+ */
+bool trans_stream_trans_full(
+    struct trans_stream_backend *backend, void **data,
+    const uint8_t *in, uint32_t in_size,
+    uint8_t *out, uint32_t out_size,
+    enum trans_stream_error *error);
+
+const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void);
+const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void);
+const struct trans_stream_backend* trans_stream_get_pipe_backend(void);
+
+extern const struct trans_stream_backend zlib_deflate_backend;
+extern const struct trans_stream_backend zlib_inflate_backend;
+extern const struct trans_stream_backend pipe_backend;
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/string/stdstring.h b/deps/libretro-common/include/string/stdstring.h
new file mode 100644 (file)
index 0000000..79fa409
--- /dev/null
@@ -0,0 +1,387 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (stdstring.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_STDSTRING_H
+#define __LIBRETRO_SDK_STDSTRING_H
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+#include <boolean.h>
+
+#include <retro_common_api.h>
+#include <retro_inline.h>
+#include <compat/strl.h>
+
+RETRO_BEGIN_DECLS
+
+#define STRLEN_CONST(x)                   ((sizeof((x))-1))
+
+#define strcpy_literal(a, b)              strcpy(a, b)
+
+#define string_is_not_equal(a, b)         !string_is_equal((a), (b))
+
+#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
+#define string_is_equal_fast(a, b, size)     (memcmp(a, b, size) == 0)
+
+#define TOLOWER(c)   ((c) |  (lr_char_props[(unsigned char)(c)] & 0x20))
+#define TOUPPER(c)   ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))
+
+/* C standard says \f \v are space, but this one disagrees */
+#define ISSPACE(c)   (lr_char_props[(unsigned char)(c)] & 0x80) 
+
+#define ISDIGIT(c)   (lr_char_props[(unsigned char)(c)] & 0x40)
+#define ISALPHA(c)   (lr_char_props[(unsigned char)(c)] & 0x20)
+#define ISLOWER(c)   (lr_char_props[(unsigned char)(c)] & 0x04)
+#define ISUPPER(c)   (lr_char_props[(unsigned char)(c)] & 0x02)
+#define ISALNUM(c)   (lr_char_props[(unsigned char)(c)] & 0x60)
+#define ISUALPHA(c)  (lr_char_props[(unsigned char)(c)] & 0x28)
+#define ISUALNUM(c)  (lr_char_props[(unsigned char)(c)] & 0x68)
+#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01)
+
+/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
+#define string_is_equal_noncase string_is_equal_case_insensitive
+
+static INLINE bool string_is_empty(const char *data)
+{
+   return !data || (*data == '\0');
+}
+
+static INLINE bool string_is_equal(const char *a, const char *b)
+{
+   return (a && b) ? !strcmp(a, b) : false;
+}
+
+static INLINE bool string_starts_with_size(const char *str, const char *prefix,
+      size_t size)
+{
+   return (str && prefix) ? !strncmp(prefix, str, size) : false;
+}
+
+static INLINE bool string_starts_with(const char *str, const char *prefix)
+{
+   return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
+}
+
+static INLINE bool string_ends_with_size(const char *str, const char *suffix,
+      size_t str_len, size_t suffix_len)
+{
+   return (str_len < suffix_len) ? false :
+         !memcmp(suffix, str + (str_len - suffix_len), suffix_len);
+}
+
+static INLINE bool string_ends_with(const char *str, const char *suffix)
+{
+   return str && suffix && string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
+}
+
+/**
+ * strlen_size:
+ *
+ * Leaf function.
+ *
+ * @return the length of 'str' (c.f. strlen()), but only
+ * checks the first 'size' characters
+ * - If 'str' is NULL, returns 0
+ * - If 'str' is not NULL and no '\0' character is found
+ *   in the first 'size' characters, returns 'size'
+ **/
+static INLINE size_t strlen_size(const char *str, size_t size)
+{
+   size_t i = 0;
+   if (str)
+      while (i < size && str[i]) i++;
+   return i;
+}
+
+
+static INLINE bool string_is_equal_case_insensitive(const char *a,
+      const char *b)
+{
+   int result              = 0;
+   const unsigned char *p1 = (const unsigned char*)a;
+   const unsigned char *p2 = (const unsigned char*)b;
+
+   if (!a || !b)
+      return false;
+   if (p1 == p2)
+      return true;
+
+   while ((result = tolower (*p1) - tolower (*p2++)) == 0)
+      if (*p1++ == '\0')
+         break;
+
+   return (result == 0);
+}
+
+static INLINE bool string_starts_with_case_insensitive(const char *str,
+      const char *prefix)
+{
+   int result              = 0;
+   const unsigned char *p1 = (const unsigned char*)str;
+   const unsigned char *p2 = (const unsigned char*)prefix;
+
+   if (!str || !prefix)
+      return false;
+   if (p1 == p2)
+      return true;
+
+   while ((result = tolower (*p1++) - tolower (*p2)) == 0)
+      if (*p2++ == '\0')
+         break;
+
+   return (result == 0 || *p2 == '\0');
+}
+
+char *string_to_upper(char *s);
+
+char *string_to_lower(char *s);
+
+char *string_ucwords(char *s);
+
+char *string_replace_substring(const char *in,
+      const char *pattern, size_t pattern_len,
+      const char *replacement, size_t replacement_len);
+
+/**
+ * string_trim_whitespace_left:
+ *
+ * Remove leading whitespaces
+ **/
+char *string_trim_whitespace_left(char *const s);
+
+/**
+ * string_trim_whitespace_right:
+ *
+ * Remove trailing whitespaces
+ **/
+char *string_trim_whitespace_right(char *const s);
+
+/**
+ * string_trim_whitespace:
+ *
+ * Remove leading and trailing whitespaces
+ **/
+char *string_trim_whitespace(char *const s);
+
+/**
+ * word_wrap:
+ * @dst                : pointer to destination buffer.
+ * @dst_size           : size of destination buffer.
+ * @src                : pointer to input string.
+ * @src_len            : length of @src
+ * @line_width         : max number of characters per line.
+ * @wideglyph_width    : not used, but is necessary to keep
+ *                       compatibility with word_wrap_wideglyph().
+ * @max_lines          : max lines of destination string.
+ *                       0 means no limit.
+ *
+ * Wraps string specified by 'src' to destination buffer
+ * specified by 'dst' and 'dst_size'.
+ * This function assumes that all glyphs in the string
+ * have an on-screen pixel width similar to that of
+ * regular Latin characters - i.e. it will not wrap
+ * correctly any text containing so-called 'wide' Unicode
+ * characters (e.g. CJK languages, emojis, etc.).
+ **/
+void word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,
+      int line_width, int wideglyph_width, unsigned max_lines);
+
+/**
+ * word_wrap_wideglyph:
+ * @dst                : pointer to destination buffer.
+ * @dst_size           : size of destination buffer.
+ * @src                : pointer to input string.
+ * @src_len            : length of @src
+ * @line_width         : max number of characters per line.
+ * @wideglyph_width    : effective width of 'wide' Unicode glyphs.
+ *                       the value here is normalised relative to the
+ *                       typical on-screen pixel width of a regular
+ *                       Latin character:
+ *                       - a regular Latin character is defined to
+ *                         have an effective width of 100
+ *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
+ *                       - e.g. if 'wide' Unicode characters in 'src'
+ *                         have an on-screen pixel width twice that of
+ *                         regular Latin characters, wideglyph_width
+ *                         would be 200
+ * @max_lines          : max lines of destination string.
+ *                       0 means no limit.
+ *
+ * Wraps string specified by @src to destination buffer
+ * specified by @dst and @dst_size.
+ * This function assumes that all glyphs in the string
+ * are:
+ * - EITHER 'non-wide' Unicode glyphs, with an on-screen
+ *   pixel width similar to that of regular Latin characters
+ * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
+ *   with an on-screen pixel width defined by @wideglyph_width
+ * Note that wrapping may occur in inappropriate locations
+ * if @src string contains 'wide' Unicode characters whose
+ * on-screen pixel width deviates greatly from the set
+ * @wideglyph_width value.
+ **/
+void word_wrap_wideglyph(
+      char *dst, size_t dst_size,
+      const char *src, size_t src_len,
+      int line_width, int wideglyph_width,
+      unsigned max_lines);
+
+/**
+ * string_tokenize:
+ *
+ * Splits string into tokens seperated by @delim
+ * > Returned token string must be free()'d
+ * > Returns NULL if token is not found
+ * > After each call, @str is set to the position after the
+ *   last found token
+ * > Tokens *include* empty strings
+ * Usage example:
+ *    char *str      = "1,2,3,4,5,6,7,,,10,";
+ *    char **str_ptr = &str;
+ *    char *token    = NULL;
+ *    while ((token = string_tokenize(str_ptr, ",")))
+ *    {
+ *        printf("%s\n", token);
+ *        free(token);
+ *        token = NULL;
+ *    }
+ **/
+char* string_tokenize(char **str, const char *delim);
+
+/**
+ * string_remove_all_chars:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ *
+ * Leaf function.
+ *
+ * Removes every instance of character @c from @str
+ **/
+void string_remove_all_chars(char *str, char c);
+
+/**
+ * string_replace_all_chars:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ * @find               : character to find
+ * @replace            : character to replace @find with
+ *
+ * Hidden non-leaf function cost:
+ * - Calls strchr (in a loop)
+ *
+ * Replaces every instance of character @find in @str
+ * with character @replace
+ **/
+void string_replace_all_chars(char *str, char find, char replace);
+
+/**
+ * string_to_unsigned:
+ * @str                : input string
+ *
+ * Converts string to unsigned integer.
+ *
+ * @return 0 if string is invalid, otherwise > 0
+ **/
+unsigned string_to_unsigned(const char *str);
+
+/**
+ * string_hex_to_unsigned:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ *
+ * Converts hexadecimal string to unsigned integer.
+ * Handles optional leading '0x'.
+ *
+ * @return 0 if string is invalid, otherwise > 0
+ **/
+unsigned string_hex_to_unsigned(const char *str);
+
+char *string_init(const char *src);
+
+void string_set(char **string, const char *src);
+
+/**
+ * string_count_occurrences_single_character:
+ *
+ * Leaf function.
+ *
+ * Get the total number of occurrences of character @c in @str.
+ *
+ * @return Total number of occurrences of character @c
+ */
+int string_count_occurrences_single_character(const char *str, char c);
+
+/**
+ * string_replace_whitespace_with_single_character:
+ * 
+ * Leaf function.
+ *
+ * Replaces all spaces with given character @c.
+ **/
+void string_replace_whitespace_with_single_character(char *str, char c);
+
+/**
+ * string_replace_multi_space_with_single_space:
+ *
+ * Leaf function.
+ *
+ * Replaces multiple spaces with a single space in a string.
+ **/
+void string_replace_multi_space_with_single_space(char *str);
+
+/**
+ * string_remove_all_whitespace:
+ *
+ * Leaf function.
+ *
+ * Remove all spaces from the given string.
+ **/
+void string_remove_all_whitespace(char *str_trimmed, const char *str);
+
+/* Retrieve the last occurance of the given character in a string. */
+int string_index_last_occurance(const char *str, char c);
+
+/**
+ * string_find_index_substring_string:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ * @substr             : substring to find in @str
+ *
+ * Hidden non-leaf function cost:
+ * - Calls strstr
+ *
+ * Find the position of substring @substr in string @str.
+ **/
+int string_find_index_substring_string(const char *str, const char *substr);
+
+/**
+ * string_copy_only_ascii:
+ *
+ * Leaf function.
+ *
+ * Strips non-ASCII characters from a string.
+ **/
+void string_copy_only_ascii(char *str_stripped, const char *str);
+
+extern const unsigned char lr_char_props[256];
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/time/rtime.h b/deps/libretro-common/include/time/rtime.h
new file mode 100644 (file)
index 0000000..7629c1e
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rtime.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_RTIME_H__
+#define __LIBRETRO_SDK_RTIME_H__
+
+#include <retro_common_api.h>
+
+#include <stdint.h>
+#include <stddef.h>
+#include <time.h>
+
+RETRO_BEGIN_DECLS
+
+/* TODO/FIXME: Move all generic time handling functions
+ * to this file */
+
+/* Must be called before using rtime_localtime() */
+void rtime_init(void);
+
+/* Must be called upon program termination */
+void rtime_deinit(void);
+
+/* Thread-safe wrapper for localtime() */
+struct tm *rtime_localtime(const time_t *timep, struct tm *result);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/utils/md5.h b/deps/libretro-common/include/utils/md5.h
new file mode 100644 (file)
index 0000000..caf160b
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 <solar at openwall.com>
+ *
+ * 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 <openssl/md5.h>
+#elif !defined(_MD5_H)
+#define _MD5_H
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/* 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);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/vfs/vfs.h b/deps/libretro-common/include/vfs/vfs.h
new file mode 100644 (file)
index 0000000..bd61c69
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation.h).
+* ---------------------------------------------------------------------------------------
+*
+* 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 __LIBRETRO_SDK_VFS_H
+#define __LIBRETRO_SDK_VFS_H
+
+#include <retro_common_api.h>
+#include <boolean.h>
+
+#ifdef RARCH_INTERNAL
+#ifndef VFS_FRONTEND
+#define VFS_FRONTEND
+#endif
+#endif
+
+RETRO_BEGIN_DECLS
+
+#ifdef _WIN32
+typedef void* HANDLE;
+#endif
+
+#ifdef HAVE_CDROM
+typedef struct
+{
+   int64_t byte_pos;
+   char *cue_buf;
+   size_t cue_len;
+   unsigned cur_lba;
+   unsigned last_frame_lba;
+   unsigned char cur_min;
+   unsigned char cur_sec;
+   unsigned char cur_frame;
+   unsigned char cur_track;
+   unsigned char last_frame[2352];
+   char drive;
+   bool last_frame_valid;
+} vfs_cdrom_t;
+#endif
+
+enum vfs_scheme
+{
+   VFS_SCHEME_NONE = 0,
+   VFS_SCHEME_CDROM
+};
+
+#if !(defined(__WINRT__) && defined(__cplusplus_winrt))
+#ifdef VFS_FRONTEND
+struct retro_vfs_file_handle
+#else
+struct libretro_vfs_implementation_file
+#endif
+{
+#ifdef HAVE_CDROM
+   vfs_cdrom_t cdrom; /* int64_t alignment */
+#endif
+   int64_t size;
+   uint64_t mappos;
+   uint64_t mapsize;
+   FILE *fp;
+#ifdef _WIN32
+   HANDLE fh;
+#endif
+   char *buf;
+   char* orig_path;
+   uint8_t *mapped;
+   int fd;
+   unsigned hints;
+   enum vfs_scheme scheme;
+};
+#endif
+
+/* Replace the following symbol with something appropriate
+ * to signify the file is being compiled for a front end instead of a core.
+ * This allows the same code to act as reference implementation
+ * for VFS and as fallbacks for when the front end does not provide VFS functionality.
+ */
+
+#ifdef VFS_FRONTEND
+typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
+#else
+typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;
+#endif
+
+#ifdef VFS_FRONTEND
+typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
+#else
+typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
+#endif
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/vfs/vfs_implementation.h b/deps/libretro-common/include/vfs/vfs_implementation.h
new file mode 100644 (file)
index 0000000..b88d2f3
--- /dev/null
@@ -0,0 +1,82 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation.h).
+* ---------------------------------------------------------------------------------------
+*
+* 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 __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
+#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <libretro.h>
+#include <retro_environment.h>
+#include <vfs/vfs.h>
+
+RETRO_BEGIN_DECLS
+
+libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);
+
+int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);
+
+int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);
+
+int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);
+
+int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len);
+
+int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len);
+
+int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream);
+
+int retro_vfs_file_remove_impl(const char *path);
+
+int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);
+
+const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);
+
+int retro_vfs_stat_impl(const char *path, int32_t *size);
+
+int retro_vfs_mkdir_impl(const char *dir);
+
+libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);
+
+bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);
+
+const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);
+
+bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
+
+int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
+
+#ifdef __WINRT__
+
+void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);
+
+#endif
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/vfs/vfs_implementation_cdrom.h b/deps/libretro-common/include/vfs/vfs_implementation_cdrom.h
new file mode 100644 (file)
index 0000000..f809963
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (vfs_implementation_cdrom.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
+#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H
+
+#include <vfs/vfs.h>
+#include <cdrom/cdrom.h>
+
+RETRO_BEGIN_DECLS
+
+int64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence);
+
+void retro_vfs_file_open_cdrom(
+      libretro_vfs_implementation_file *stream,
+      const char *path, unsigned mode, unsigned hints);
+
+int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
+      void *s, uint64_t len);
+
+int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream);
+
+const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void);
+
+const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/deps/libretro-common/include/vulkan/vulkan_symbol_wrapper.h b/deps/libretro-common/include/vulkan/vulkan_symbol_wrapper.h
new file mode 100644 (file)
index 0000000..4df6e88
--- /dev/null
@@ -0,0 +1,347 @@
+
+/* This header is autogenerated by vulkan_loader_generator.py */
+#ifndef VULKAN_SYMBOL_WRAPPER_H
+#define VULKAN_SYMBOL_WRAPPER_H
+#define VK_NO_PROTOTYPES
+#include <vulkan/vulkan.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern PFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;
+#define vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance
+extern PFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;
+#define vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion
+extern PFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;
+#define vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties
+extern PFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;
+#define vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties
+extern PFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;
+#define vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance
+extern PFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;
+#define vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices
+extern PFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;
+#define vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures
+extern PFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;
+#define vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties
+extern PFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;
+#define vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties
+extern PFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;
+#define vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties
+extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;
+#define vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties
+extern PFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;
+#define vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties
+extern PFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;
+#define vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr
+extern PFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;
+#define vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice
+extern PFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;
+#define vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice
+extern PFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;
+#define vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties
+extern PFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;
+#define vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties
+extern PFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;
+#define vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue
+extern PFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;
+#define vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit
+extern PFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;
+#define vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle
+extern PFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;
+#define vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle
+extern PFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;
+#define vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory
+extern PFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;
+#define vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory
+extern PFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;
+#define vkMapMemory vulkan_symbol_wrapper_vkMapMemory
+extern PFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;
+#define vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory
+extern PFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;
+#define vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges
+extern PFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;
+#define vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges
+extern PFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;
+#define vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment
+extern PFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;
+#define vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory
+extern PFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;
+#define vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory
+extern PFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;
+#define vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements
+extern PFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;
+#define vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements
+extern PFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;
+#define vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements
+extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;
+#define vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties
+extern PFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;
+#define vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse
+extern PFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;
+#define vkCreateFence vulkan_symbol_wrapper_vkCreateFence
+extern PFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;
+#define vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence
+extern PFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;
+#define vkResetFences vulkan_symbol_wrapper_vkResetFences
+extern PFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;
+#define vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus
+extern PFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;
+#define vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences
+extern PFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;
+#define vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore
+extern PFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;
+#define vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore
+extern PFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;
+#define vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent
+extern PFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;
+#define vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent
+extern PFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;
+#define vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus
+extern PFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;
+#define vkSetEvent vulkan_symbol_wrapper_vkSetEvent
+extern PFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;
+#define vkResetEvent vulkan_symbol_wrapper_vkResetEvent
+extern PFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;
+#define vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool
+extern PFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;
+#define vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool
+extern PFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;
+#define vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults
+extern PFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;
+#define vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer
+extern PFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;
+#define vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer
+extern PFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;
+#define vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView
+extern PFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;
+#define vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView
+extern PFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;
+#define vkCreateImage vulkan_symbol_wrapper_vkCreateImage
+extern PFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;
+#define vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage
+extern PFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;
+#define vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout
+extern PFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;
+#define vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView
+extern PFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;
+#define vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView
+extern PFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;
+#define vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule
+extern PFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;
+#define vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule
+extern PFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;
+#define vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache
+extern PFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;
+#define vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache
+extern PFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;
+#define vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData
+extern PFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;
+#define vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches
+extern PFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;
+#define vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines
+extern PFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;
+#define vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines
+extern PFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;
+#define vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline
+extern PFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;
+#define vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout
+extern PFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;
+#define vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout
+extern PFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;
+#define vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler
+extern PFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;
+#define vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler
+extern PFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;
+#define vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout
+extern PFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;
+#define vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout
+extern PFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;
+#define vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool
+extern PFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;
+#define vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool
+extern PFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;
+#define vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool
+extern PFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;
+#define vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets
+extern PFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;
+#define vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets
+extern PFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;
+#define vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets
+extern PFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;
+#define vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer
+extern PFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;
+#define vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer
+extern PFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;
+#define vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass
+extern PFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;
+#define vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass
+extern PFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;
+#define vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity
+extern PFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;
+#define vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool
+extern PFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;
+#define vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool
+extern PFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;
+#define vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool
+extern PFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;
+#define vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers
+extern PFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;
+#define vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers
+extern PFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;
+#define vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer
+extern PFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;
+#define vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer
+extern PFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;
+#define vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer
+extern PFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;
+#define vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline
+extern PFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;
+#define vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport
+extern PFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;
+#define vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor
+extern PFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;
+#define vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth
+extern PFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;
+#define vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias
+extern PFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;
+#define vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants
+extern PFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;
+#define vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds
+extern PFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;
+#define vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask
+extern PFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;
+#define vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask
+extern PFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;
+#define vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference
+extern PFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;
+#define vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets
+extern PFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;
+#define vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer
+extern PFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;
+#define vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers
+extern PFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;
+#define vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw
+extern PFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;
+#define vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed
+extern PFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;
+#define vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect
+extern PFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;
+#define vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect
+extern PFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;
+#define vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch
+extern PFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;
+#define vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect
+extern PFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;
+#define vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer
+extern PFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;
+#define vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage
+extern PFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;
+#define vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage
+extern PFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;
+#define vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage
+extern PFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;
+#define vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer
+extern PFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;
+#define vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer
+extern PFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;
+#define vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer
+extern PFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;
+#define vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage
+extern PFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;
+#define vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage
+extern PFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;
+#define vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments
+extern PFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;
+#define vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage
+extern PFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;
+#define vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent
+extern PFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;
+#define vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent
+extern PFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;
+#define vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents
+extern PFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;
+#define vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier
+extern PFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;
+#define vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery
+extern PFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;
+#define vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery
+extern PFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;
+#define vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool
+extern PFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;
+#define vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp
+extern PFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;
+#define vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults
+extern PFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;
+#define vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants
+extern PFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;
+#define vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass
+extern PFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;
+#define vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass
+extern PFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;
+#define vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass
+extern PFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;
+#define vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands
+extern PFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;
+#define vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR
+extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;
+#define vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR
+extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
+#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
+extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;
+#define vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR
+extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;
+#define vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR
+extern PFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;
+#define vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR
+extern PFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;
+#define vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR
+extern PFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;
+#define vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR
+extern PFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;
+#define vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR
+extern PFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;
+#define vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR
+extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;
+#define vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR
+extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
+#define vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR
+extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;
+#define vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR
+extern PFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;
+#define vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR
+extern PFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;
+#define vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR
+extern PFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;
+#define vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR
+extern PFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;
+#define vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR
+extern PFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;
+#define vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR
+
+extern PFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;
+#define vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT
+extern PFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;
+#define vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT
+extern PFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;
+#define vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT
+
+void vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr);
+PFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void);
+VkBool32 vulkan_symbol_wrapper_load_global_symbols(void);
+VkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance);
+VkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance);
+VkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device);
+VkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol);
+VkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol);
+
+#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, name, pfn) vulkan_symbol_wrapper_load_instance_symbol(instance, name, (PFN_vkVoidFunction*) &(pfn))
+#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, name) vulkan_symbol_wrapper_load_instance_symbol(instance, #name, (PFN_vkVoidFunction*) & name)
+#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, name, pfn) vulkan_symbol_wrapper_load_device_symbol(device, name, (PFN_vkVoidFunction*) &(pfn))
+#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, name) vulkan_symbol_wrapper_load_device_symbol(device, #name, (PFN_vkVoidFunction*) & name)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/deps/libretro-common/libco/aarch64.c b/deps/libretro-common/libco/aarch64.c
new file mode 100644 (file)
index 0000000..516443f
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+  libco.aarch64 (2017-06-26)
+  author: webgeek1234
+  license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#ifndef __APPLE__
+#include <malloc.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local uint64_t co_active_buffer[64];
+static thread_local cothread_t co_active_handle;
+
+asm (
+      ".globl co_switch_aarch64\n"
+      ".globl _co_switch_aarch64\n"
+      "co_switch_aarch64:\n"
+      "_co_switch_aarch64:\n"
+      "  stp x8,  x9,  [x1]\n"
+      "  stp x10, x11, [x1, #16]\n"
+      "  stp x12, x13, [x1, #32]\n"
+      "  stp x14, x15, [x1, #48]\n"
+      "  str x19, [x1, #72]\n"
+      "  stp x20, x21, [x1, #80]\n"
+      "  stp x22, x23, [x1, #96]\n"
+      "  stp x24, x25, [x1, #112]\n"
+      "  stp x26, x27, [x1, #128]\n"
+      "  stp x28, x29, [x1, #144]\n"
+      "  mov x16, sp\n"
+      "  stp x16, x30, [x1, #160]\n"
+
+      "  ldp x8,  x9,  [x0]\n"
+      "  ldp x10, x11, [x0, #16]\n"
+      "  ldp x12, x13, [x0, #32]\n"
+      "  ldp x14, x15, [x0, #48]\n"
+      "  ldr x19, [x0, #72]\n"
+      "  ldp x20, x21, [x0, #80]\n"
+      "  ldp x22, x23, [x0, #96]\n"
+      "  ldp x24, x25, [x0, #112]\n"
+      "  ldp x26, x27, [x0, #128]\n"
+      "  ldp x28, x29, [x0, #144]\n"
+      "  ldp x16, x17, [x0, #160]\n"
+      "  mov sp, x16\n"
+      "  br x17\n"
+    );
+
+/* ASM */
+void co_switch_aarch64(cothread_t handle, cothread_t current);
+
+static void crash(void)
+{
+   /* Called only if cothread_t entrypoint returns. */
+   assert(0);
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void))
+{
+       uint64_t *ptr     = NULL;
+   cothread_t handle = 0;
+   size              = (size + 1023) & ~1023;
+#if HAVE_POSIX_MEMALIGN >= 1
+   if (posix_memalign(&handle, 1024, size + 512) < 0)
+      return 0;
+#else
+   handle            = memalign(1024, size + 512);
+#endif
+
+   if (!handle)
+      return handle;
+
+   ptr     = (uint64_t*)handle;
+   /* Non-volatiles.  */
+   ptr[0]  = 0; /* x8  */
+   ptr[1]  = 0; /* x9  */
+   ptr[2]  = 0; /* x10 */
+   ptr[3]  = 0; /* x11 */
+   ptr[4]  = 0; /* x12 */
+   ptr[5]  = 0; /* x13 */
+   ptr[6]  = 0; /* x14 */
+   ptr[7]  = 0; /* x15 */
+   ptr[8]  = 0; /* padding */
+   ptr[9]  = 0; /* x19 */
+   ptr[10] = 0; /* x20 */
+   ptr[11] = 0; /* x21 */
+   ptr[12] = 0; /* x22 */
+   ptr[13] = 0; /* x23 */
+   ptr[14] = 0; /* x24 */
+   ptr[15] = 0; /* x25 */
+   ptr[16] = 0; /* x26 */
+   ptr[17] = 0; /* x27 */
+   ptr[18] = 0; /* x28 */
+   ptr[20] = (uintptr_t)ptr + size + 512 - 16; /* x30, stack pointer */
+   ptr[19] = ptr[20]; /* x29, frame pointer */
+   ptr[21] = (uintptr_t)entrypoint; /* PC (link register x31 gets saved here). */
+   return handle;
+}
+
+cothread_t co_active(void)
+{
+   if (!co_active_handle)
+      co_active_handle = co_active_buffer;
+   return co_active_handle;
+}
+
+void co_delete(cothread_t handle)
+{
+   free(handle);
+}
+
+void co_switch(cothread_t handle)
+{
+   cothread_t co_previous_handle = co_active();
+   co_switch_aarch64(co_active_handle = handle, co_previous_handle);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/amd64.c b/deps/libretro-common/libco/amd64.c
new file mode 100644 (file)
index 0000000..54b1abf
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+  libco.amd64 (2009-10-12)
+  author: byuu
+  license: public domain
+*/
+
+#define LIBCO_C
+#include <libco.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#if defined(__GNUC__) && !defined(_WIN32) && !defined(__cplusplus)
+#define CO_USE_INLINE_ASM
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local long long co_active_buffer[64];
+static thread_local cothread_t co_active_handle = 0;
+#ifndef CO_USE_INLINE_ASM
+static void (*co_swap)(cothread_t, cothread_t)  = 0;
+#endif
+
+#ifdef _WIN32
+/* ABI: Win64 */
+  /* On windows handle is allocated by malloc and there it's guaranteed to
+     have at least 16-byte alignment. Hence we don't need to align
+     it in order to use movaps.  */
+static unsigned char co_swap_function[] = {
+    0x48, 0x89, 0x22,              /* mov [rdx],rsp          */
+    0x48, 0x8b, 0x21,              /* mov rsp,[rcx]          */
+    0x58,                          /* pop rax                */
+    0x48, 0x89, 0x6a, 0x08,        /* mov [rdx+ 8],rbp       */
+    0x48, 0x89, 0x72, 0x10,        /* mov [rdx+16],rsi       */
+    0x48, 0x89, 0x7a, 0x18,        /* mov [rdx+24],rdi       */
+    0x48, 0x89, 0x5a, 0x20,        /* mov [rdx+32],rbx       */
+    0x4c, 0x89, 0x62, 0x28,        /* mov [rdx+40],r12       */
+    0x4c, 0x89, 0x6a, 0x30,        /* mov [rdx+48],r13       */
+    0x4c, 0x89, 0x72, 0x38,        /* mov [rdx+56],r14       */
+    0x4c, 0x89, 0x7a, 0x40,        /* mov [rdx+64],r15       */
+  #if !defined(LIBCO_NO_SSE)
+    0x0f, 0x29, 0x72, 0x50,        /* movaps [rdx+ 80],xmm6  */
+    0x0f, 0x29, 0x7a, 0x60,        /* movaps [rdx+ 96],xmm7  */
+    0x44, 0x0f, 0x29, 0x42, 0x70,  /* movaps [rdx+112],xmm8  */
+    0x48, 0x83, 0xc2, 0x70,        /* add rdx,112            */
+    0x44, 0x0f, 0x29, 0x4a, 0x10,  /* movaps [rdx+ 16],xmm9  */
+    0x44, 0x0f, 0x29, 0x52, 0x20,  /* movaps [rdx+ 32],xmm10 */
+    0x44, 0x0f, 0x29, 0x5a, 0x30,  /* movaps [rdx+ 48],xmm11 */
+    0x44, 0x0f, 0x29, 0x62, 0x40,  /* movaps [rdx+ 64],xmm12 */
+    0x44, 0x0f, 0x29, 0x6a, 0x50,  /* movaps [rdx+ 80],xmm13 */
+    0x44, 0x0f, 0x29, 0x72, 0x60,  /* movaps [rdx+ 96],xmm14 */
+    0x44, 0x0f, 0x29, 0x7a, 0x70,  /* movaps [rdx+112],xmm15 */
+  #endif
+    0x48, 0x8b, 0x69, 0x08,        /* mov rbp,[rcx+ 8]       */
+    0x48, 0x8b, 0x71, 0x10,        /* mov rsi,[rcx+16]       */
+    0x48, 0x8b, 0x79, 0x18,        /* mov rdi,[rcx+24]       */
+    0x48, 0x8b, 0x59, 0x20,        /* mov rbx,[rcx+32]       */
+    0x4c, 0x8b, 0x61, 0x28,        /* mov r12,[rcx+40]       */
+    0x4c, 0x8b, 0x69, 0x30,        /* mov r13,[rcx+48]       */
+    0x4c, 0x8b, 0x71, 0x38,        /* mov r14,[rcx+56]       */
+    0x4c, 0x8b, 0x79, 0x40,        /* mov r15,[rcx+64]       */
+  #if !defined(LIBCO_NO_SSE)
+    0x0f, 0x28, 0x71, 0x50,        /* movaps xmm6, [rcx+ 80] */
+    0x0f, 0x28, 0x79, 0x60,        /* movaps xmm7, [rcx+ 96] */
+    0x44, 0x0f, 0x28, 0x41, 0x70,  /* movaps xmm8, [rcx+112] */
+    0x48, 0x83, 0xc1, 0x70,        /* add rcx,112            */
+    0x44, 0x0f, 0x28, 0x49, 0x10,  /* movaps xmm9, [rcx+ 16] */
+    0x44, 0x0f, 0x28, 0x51, 0x20,  /* movaps xmm10,[rcx+ 32] */
+    0x44, 0x0f, 0x28, 0x59, 0x30,  /* movaps xmm11,[rcx+ 48] */
+    0x44, 0x0f, 0x28, 0x61, 0x40,  /* movaps xmm12,[rcx+ 64] */
+    0x44, 0x0f, 0x28, 0x69, 0x50,  /* movaps xmm13,[rcx+ 80] */
+    0x44, 0x0f, 0x28, 0x71, 0x60,  /* movaps xmm14,[rcx+ 96] */
+    0x44, 0x0f, 0x28, 0x79, 0x70,  /* movaps xmm15,[rcx+112] */
+  #endif
+    0xff, 0xe0,                    /* jmp rax                */
+};
+
+#include <windows.h>
+
+static void co_init(void)
+{
+   DWORD old_privileges;
+   VirtualProtect(co_swap_function,
+         sizeof(co_swap_function), PAGE_EXECUTE_READWRITE, &old_privileges);
+}
+#else
+/* ABI: SystemV */
+#ifndef CO_USE_INLINE_ASM
+static unsigned char co_swap_function[] = {
+  0x48, 0x89, 0x26,                                 /* mov    [rsi],rsp      */
+  0x48, 0x8b, 0x27,                                 /* mov    rsp,[rdi]      */
+  0x58,                                             /* pop    rax            */
+  0x48, 0x89, 0x6e, 0x08,                           /* mov    [rsi+0x08],rbp */
+  0x48, 0x89, 0x5e, 0x10,                           /* mov    [rsi+0x10],rbx */
+  0x4c, 0x89, 0x66, 0x18,                           /* mov    [rsi+0x18],r12 */
+  0x4c, 0x89, 0x6e, 0x20,                           /* mov    [rsi+0x20],r13 */
+  0x4c, 0x89, 0x76, 0x28,                           /* mov    [rsi+0x28],r14 */
+  0x4c, 0x89, 0x7e, 0x30,                           /* mov    [rsi+0x30],r15 */
+  0x48, 0x8b, 0x6f, 0x08,                           /* mov    rbp,[rdi+0x08] */
+  0x48, 0x8b, 0x5f, 0x10,                           /* mov    rbx,[rdi+0x10] */
+  0x4c, 0x8b, 0x67, 0x18,                           /* mov    r12,[rdi+0x18] */
+  0x4c, 0x8b, 0x6f, 0x20,                           /* mov    r13,[rdi+0x20] */
+  0x4c, 0x8b, 0x77, 0x28,                           /* mov    r14,[rdi+0x28] */
+  0x4c, 0x8b, 0x7f, 0x30,                           /* mov    r15,[rdi+0x30] */
+  0xff, 0xe0,                                       /* jmp    rax            */
+};
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+static void co_init(void)
+{
+   unsigned long long addr = (unsigned long long)co_swap_function;
+   unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
+   unsigned long long size = (addr - base) + sizeof(co_swap_function);
+   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
+}
+#else
+static void co_init(void) {}
+#endif
+#endif
+
+static void crash(void)
+{
+  assert(0); /* called only if cothread_t entrypoint returns */
+}
+
+cothread_t co_active(void)
+{
+  if (!co_active_handle)
+     co_active_handle = &co_active_buffer;
+  return co_active_handle;
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void))
+{
+   cothread_t handle;
+#ifndef CO_USE_INLINE_ASM
+   if (!co_swap)
+   {
+      co_init();
+      co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
+   }
+#endif
+
+   if (!co_active_handle)
+      co_active_handle = &co_active_buffer;
+   size += 512; /* allocate additional space for storage */
+   size &= ~15; /* align stack to 16-byte boundary */
+
+#ifdef __GENODE__
+   if ((handle = (cothread_t)genode_alloc_secondary_stack(size)))
+   {
+      long long *p        = (long long*)((char*)handle); /* OS returns top of stack */
+      *--p                = (long long)crash;            /* crash if entrypoint returns */
+      *--p                = (long long)entrypoint;       /* start of function */
+      *(long long*)handle = (long long)p;                /* stack pointer */
+   }
+#else
+   if ((handle = (cothread_t)malloc(size)))
+   {
+      long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
+      *--p = (long long)crash;                           /* crash if entrypoint returns */
+      *--p = (long long)entrypoint;                      /* start of function */
+      *(long long*)handle = (long long)p;                /* stack pointer */
+   }
+#endif
+
+   return handle;
+}
+
+void co_delete(cothread_t handle)
+{
+#ifdef __GENODE__
+   genode_free_secondary_stack(handle);
+#else
+   free(handle);
+#endif
+}
+
+#ifndef CO_USE_INLINE_ASM
+void co_switch(cothread_t handle)
+{
+  register cothread_t co_previous_handle = co_active_handle;
+  co_swap(co_active_handle = handle, co_previous_handle);
+}
+#else
+#ifdef __APPLE__
+#define ASM_PREFIX "_"
+#else
+#define ASM_PREFIX ""
+#endif
+__asm__(
+".intel_syntax noprefix         \n"
+".globl " ASM_PREFIX "co_switch              \n"
+ASM_PREFIX "co_switch:                     \n"
+"mov rsi, [rip+" ASM_PREFIX "co_active_handle]\n"
+"mov [rsi],rsp                  \n"
+"mov [rsi+0x08],rbp             \n"
+"mov [rsi+0x10],rbx             \n"
+"mov [rsi+0x18],r12             \n"
+"mov [rsi+0x20],r13             \n"
+"mov [rsi+0x28],r14             \n"
+"mov [rsi+0x30],r15             \n"
+"mov [rip+" ASM_PREFIX "co_active_handle], rdi\n"
+"mov rsp,[rdi]                  \n"
+"mov rbp,[rdi+0x08]             \n"
+"mov rbx,[rdi+0x10]             \n"
+"mov r12,[rdi+0x18]             \n"
+"mov r13,[rdi+0x20]             \n"
+"mov r14,[rdi+0x28]             \n"
+"mov r15,[rdi+0x30]             \n"
+"ret                            \n"
+".att_syntax                    \n"
+);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/armeabi.c b/deps/libretro-common/libco/armeabi.c
new file mode 100644 (file)
index 0000000..d3efd40
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+  libco.armeabi (2013-04-05)
+  author: Themaister
+  license: public domain
+*/
+
+#define LIBCO_C
+#include <libco.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#ifndef __APPLE__
+#include <malloc.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local uint32_t co_active_buffer[64];
+static thread_local cothread_t co_active_handle;
+
+__asm__ (
+#if defined(__thumb2__)
+      ".align 2\n"
+      ".globl co_switch_arm\n"
+      ".globl _co_switch_arm\n"
+      ".thumb\n"
+      ".thumb_func\n"
+      ".type   co_switch_arm, %function\n"
+      ".type   _co_switch_arm, %function\n"
+      "co_switch_arm:\n"
+      "_co_switch_arm:\n"
+      " mov r3, sp\n"
+      " stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
+      " stmia r1!, {r3, lr}\n"
+      " ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
+      " ldmfd r0!, { r3 }\n"
+      " mov sp, r3\n"
+      " ldmfd r0!, { r3 }\n"
+      " mov pc, r3\n"
+#else
+      ".arm\n"
+      ".align 4\n"
+      ".globl co_switch_arm\n"
+      ".globl _co_switch_arm\n"
+      "co_switch_arm:\n"
+      "_co_switch_arm:\n"
+      "  stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\n"
+      "  ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\n"
+#endif
+    );
+
+/* ASM */
+void co_switch_arm(cothread_t handle, cothread_t current);
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void))
+{
+   uint32_t *ptr     = NULL;
+   cothread_t handle = 0;
+   size              = (size + 1023) & ~1023;
+#if defined(__APPLE__) || HAVE_POSIX_MEMALIGN >= 1
+   if (posix_memalign(&handle, 1024, size + 256) < 0)
+      return 0;
+#else
+   handle = memalign(1024, size + 256);
+#endif
+
+   if (!handle)
+      return handle;
+
+   ptr    = (uint32_t*)handle;
+   /* Non-volatiles.  */
+   ptr[0] = 0; /* r4  */
+   ptr[1] = 0; /* r5  */
+   ptr[2] = 0; /* r6  */
+   ptr[3] = 0; /* r7  */
+   ptr[4] = 0; /* r8  */
+   ptr[5] = 0; /* r9  */
+   ptr[6] = 0; /* r10 */
+   ptr[7] = 0; /* r11 */
+   /* Align stack to 64-bit */
+   ptr[8] = (uintptr_t)ptr + size + 256 - 8; /* r13, stack pointer */
+   ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */
+   return handle;
+}
+
+cothread_t co_active(void)
+{
+   if (!co_active_handle)
+      co_active_handle = co_active_buffer;
+   return co_active_handle;
+}
+
+void co_delete(cothread_t handle)
+{
+   free(handle);
+}
+
+void co_switch(cothread_t handle)
+{
+   cothread_t co_previous_handle = co_active();
+   co_switch_arm(co_active_handle = handle, co_previous_handle);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/fiber.c b/deps/libretro-common/libco/fiber.c
new file mode 100644 (file)
index 0000000..d745926
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+  libco.win (2008-01-28)
+  authors: Nach, byuu
+  license: public domain
+*/
+
+#define LIBCO_C
+#include <libco.h>
+#define WINVER 0x0400
+#define _WIN32_WINNT 0x0400
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local cothread_t co_active_ = 0;
+
+static void __stdcall co_thunk(void *coentry)
+{
+   ((void (*)(void))coentry)();
+}
+
+cothread_t co_active(void)
+{
+   if (!co_active_)
+   {
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
+#else
+      ConvertThreadToFiber(0);
+#endif
+      co_active_ = GetCurrentFiber();
+   }
+   return co_active_;
+}
+
+cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
+{
+   if (!co_active_)
+   {
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
+#else
+      ConvertThreadToFiber(0);
+#endif
+      co_active_ = GetCurrentFiber();
+   }
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+   return (cothread_t)CreateFiberEx(heapsize, heapsize, FIBER_FLAG_FLOAT_SWITCH, co_thunk, (void*)coentry);
+#else
+   return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
+#endif
+}
+
+void co_delete(cothread_t cothread)
+{
+   DeleteFiber(cothread);
+}
+
+void co_switch(cothread_t cothread)
+{
+   co_active_ = cothread;
+   SwitchToFiber(cothread);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/genode.cpp b/deps/libretro-common/libco/genode.cpp
new file mode 100644 (file)
index 0000000..f1d671a
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+  libco.genode_secondary_stack (2018-09-15)
+  author: Emery Hemingway
+  license: public domain
+*/
+
+/* Genode include */
+#include <base/thread.h>
+
+/* Libco include */
+#include <libco.h>
+
+extern "C"
+void *genode_alloc_secondary_stack(unsigned long stack_size)
+{
+       try
+   {
+               return Genode::Thread::myself()->alloc_secondary_stack("libco", stack_size);
+   }
+       catch (...)
+   {
+               Genode::error("libco: failed to allocate ", stack_size, " byte secondary stack");
+               return nullptr;
+       }
+}
+
+extern "C"
+void genode_free_secondary_stack(void *stack)
+{
+       Genode::Thread::myself()->free_secondary_stack(stack);
+}
diff --git a/deps/libretro-common/libco/libco.c b/deps/libretro-common/libco/libco.c
new file mode 100644 (file)
index 0000000..44a65d5
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+  libco
+  auto-selection module
+  license: public domain
+*/
+
+#ifdef __GENODE__
+void *genode_alloc_secondary_stack(unsigned long stack_size);
+void genode_free_secondary_stack(void *stack);
+#endif
+
+#if defined _MSC_VER
+  #include <Windows.h>
+  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+    #include "fiber.c"
+  #elif defined _M_IX86
+    #include "x86.c"
+  #elif defined _M_AMD64
+    #include "amd64.c"
+  #else
+    #include "fiber.c"
+  #endif
+#elif defined __GNUC__
+  #if defined __i386__
+    #include "x86.c"
+  #elif defined __amd64__
+    #include "amd64.c"
+  #elif defined _ARCH_PPC
+    #include "ppc.c"
+  #elif defined(__aarch64__)
+    #include "aarch64.c"
+  #elif defined(PS2)
+    #include "ps2.c"
+  #elif defined(PSP)
+    #include "psp1.c"
+  #elif defined VITA
+    #include "scefiber.c"
+  #elif defined(__ARM_EABI__) || defined(__arm__)
+    #include "armeabi.c"
+  #else
+    #include "sjlj.c"
+  #endif
+#else
+  #error "libco: unsupported processor, compiler or operating system"
+#endif
diff --git a/deps/libretro-common/libco/ppc.c b/deps/libretro-common/libco/ppc.c
new file mode 100644 (file)
index 0000000..88faed6
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+  libco.ppc (2010-10-17)
+  author: blargg
+  license: public domain
+*/
+
+/* PowerPC 32/64 using embedded or external asm, with optional
+floating-point and AltiVec save/restore */
+
+#define LIBCO_C
+#include <libco.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)
+
+#if LIBCO_MPROTECT
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
+/* State format (offsets in 32-bit words)
+
++0     Pointer to swap code
+       Rest of function descriptor for entry function
++8     PC
++10    SP
+       Special regs
+       GPRs
+       FPRs
+       VRs
+       stack
+*/
+
+enum { state_size  = 1024 };
+enum { above_stack = 2048 };
+enum { stack_align = 256  };
+
+static thread_local cothread_t co_active_handle = 0;
+
+/**** Determine environment ****/
+
+#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
+
+/* Whether function calls are indirect through a descriptor,
+or are directly to function */
+#ifndef LIBCO_PPCDESC
+       #if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
+               #define LIBCO_PPCDESC 1
+       #endif
+#endif
+
+#ifdef LIBCO_PPC_ASM
+
+       #ifdef __cplusplus
+               extern "C"
+       #endif
+
+       /* Swap code is in ppc.S */
+       void co_swap_asm(cothread_t, cothread_t);
+       #define CO_SWAP_ASM(x, y) co_swap_asm(x, y)
+
+#else
+
+/* Swap code is here in array. Please leave dieassembly comments,
+as they make it easy to see what it does, and reorder instructions
+if one wants to see whether that improves performance. */
+static const uint32_t libco_ppc_code [] = {
+#if LIBCO_PPC64
+    0x7d000026, /* mfcr    r8 */
+    0xf8240028, /* std     r1,40(r4) */
+    0x7d2802a6, /* mflr    r9 */
+    0xf9c40048, /* std     r14,72(r4) */
+    0xf9e40050, /* std     r15,80(r4) */
+    0xfa040058, /* std     r16,88(r4) */
+    0xfa240060, /* std     r17,96(r4) */
+    0xfa440068, /* std     r18,104(r4) */
+    0xfa640070, /* std     r19,112(r4) */
+    0xfa840078, /* std     r20,120(r4) */
+    0xfaa40080, /* std     r21,128(r4) */
+    0xfac40088, /* std     r22,136(r4) */
+    0xfae40090, /* std     r23,144(r4) */
+    0xfb040098, /* std     r24,152(r4) */
+    0xfb2400a0, /* std     r25,160(r4) */
+    0xfb4400a8, /* std     r26,168(r4) */
+    0xfb6400b0, /* std     r27,176(r4) */
+    0xfb8400b8, /* std     r28,184(r4) */
+    0xfba400c0, /* std     r29,192(r4) */
+    0xfbc400c8, /* std     r30,200(r4) */
+    0xfbe400d0, /* std     r31,208(r4) */
+    0xf9240020, /* std     r9,32(r4) */
+    0xe8e30020, /* ld      r7,32(r3) */
+    0xe8230028, /* ld      r1,40(r3) */
+    0x48000009, /* bl      1 */
+       0x7fe00008, /* trap */
+    0x91040030,/*1:stw     r8,48(r4) */
+    0x80c30030, /* lwz     r6,48(r3) */
+    0x7ce903a6, /* mtctr   r7 */
+    0xe9c30048, /* ld      r14,72(r3) */
+    0xe9e30050, /* ld      r15,80(r3) */
+    0xea030058, /* ld      r16,88(r3) */
+    0xea230060, /* ld      r17,96(r3) */
+    0xea430068, /* ld      r18,104(r3) */
+    0xea630070, /* ld      r19,112(r3) */
+    0xea830078, /* ld      r20,120(r3) */
+    0xeaa30080, /* ld      r21,128(r3) */
+    0xeac30088, /* ld      r22,136(r3) */
+    0xeae30090, /* ld      r23,144(r3) */
+    0xeb030098, /* ld      r24,152(r3) */
+    0xeb2300a0, /* ld      r25,160(r3) */
+    0xeb4300a8, /* ld      r26,168(r3) */
+    0xeb6300b0, /* ld      r27,176(r3) */
+    0xeb8300b8, /* ld      r28,184(r3) */
+    0xeba300c0, /* ld      r29,192(r3) */
+    0xebc300c8, /* ld      r30,200(r3) */
+    0xebe300d0, /* ld      r31,208(r3) */
+    0x7ccff120, /* mtcr    r6 */
+#else
+       0x7d000026, /* mfcr    r8 */
+       0x90240028, /* stw     r1,40(r4) */
+       0x7d2802a6, /* mflr    r9 */
+       0x91a4003c, /* stw     r13,60(r4) */
+       0x91c40040, /* stw     r14,64(r4) */
+       0x91e40044, /* stw     r15,68(r4) */
+       0x92040048, /* stw     r16,72(r4) */
+       0x9224004c, /* stw     r17,76(r4) */
+       0x92440050, /* stw     r18,80(r4) */
+       0x92640054, /* stw     r19,84(r4) */
+       0x92840058, /* stw     r20,88(r4) */
+       0x92a4005c, /* stw     r21,92(r4) */
+       0x92c40060, /* stw     r22,96(r4) */
+       0x92e40064, /* stw     r23,100(r4) */
+       0x93040068, /* stw     r24,104(r4) */
+       0x9324006c, /* stw     r25,108(r4) */
+       0x93440070, /* stw     r26,112(r4) */
+       0x93640074, /* stw     r27,116(r4) */
+       0x93840078, /* stw     r28,120(r4) */
+       0x93a4007c, /* stw     r29,124(r4) */
+       0x93c40080, /* stw     r30,128(r4) */
+       0x93e40084, /* stw     r31,132(r4) */
+       0x91240020, /* stw     r9,32(r4) */
+       0x80e30020, /* lwz     r7,32(r3) */
+       0x80230028, /* lwz     r1,40(r3) */
+       0x48000009, /* bl      1 */
+       0x7fe00008, /* trap */
+       0x91040030,/*1:stw     r8,48(r4) */
+       0x80c30030, /* lwz     r6,48(r3) */
+       0x7ce903a6, /* mtctr   r7 */
+       0x81a3003c, /* lwz     r13,60(r3) */
+       0x81c30040, /* lwz     r14,64(r3) */
+       0x81e30044, /* lwz     r15,68(r3) */
+       0x82030048, /* lwz     r16,72(r3) */
+       0x8223004c, /* lwz     r17,76(r3) */
+       0x82430050, /* lwz     r18,80(r3) */
+       0x82630054, /* lwz     r19,84(r3) */
+       0x82830058, /* lwz     r20,88(r3) */
+       0x82a3005c, /* lwz     r21,92(r3) */
+       0x82c30060, /* lwz     r22,96(r3) */
+       0x82e30064, /* lwz     r23,100(r3) */
+       0x83030068, /* lwz     r24,104(r3) */
+       0x8323006c, /* lwz     r25,108(r3) */
+       0x83430070, /* lwz     r26,112(r3) */
+       0x83630074, /* lwz     r27,116(r3) */
+       0x83830078, /* lwz     r28,120(r3) */
+       0x83a3007c, /* lwz     r29,124(r3) */
+       0x83c30080, /* lwz     r30,128(r3) */
+       0x83e30084, /* lwz     r31,132(r3) */
+       0x7ccff120, /* mtcr    r6 */
+#endif
+
+#ifndef LIBCO_PPC_NOFP
+       0xd9c400e0, /* stfd    f14,224(r4) */
+       0xd9e400e8, /* stfd    f15,232(r4) */
+       0xda0400f0, /* stfd    f16,240(r4) */
+       0xda2400f8, /* stfd    f17,248(r4) */
+       0xda440100, /* stfd    f18,256(r4) */
+       0xda640108, /* stfd    f19,264(r4) */
+       0xda840110, /* stfd    f20,272(r4) */
+       0xdaa40118, /* stfd    f21,280(r4) */
+       0xdac40120, /* stfd    f22,288(r4) */
+       0xdae40128, /* stfd    f23,296(r4) */
+       0xdb040130, /* stfd    f24,304(r4) */
+       0xdb240138, /* stfd    f25,312(r4) */
+       0xdb440140, /* stfd    f26,320(r4) */
+       0xdb640148, /* stfd    f27,328(r4) */
+       0xdb840150, /* stfd    f28,336(r4) */
+       0xdba40158, /* stfd    f29,344(r4) */
+       0xdbc40160, /* stfd    f30,352(r4) */
+       0xdbe40168, /* stfd    f31,360(r4) */
+       0xc9c300e0, /* lfd     f14,224(r3) */
+       0xc9e300e8, /* lfd     f15,232(r3) */
+       0xca0300f0, /* lfd     f16,240(r3) */
+       0xca2300f8, /* lfd     f17,248(r3) */
+       0xca430100, /* lfd     f18,256(r3) */
+       0xca630108, /* lfd     f19,264(r3) */
+       0xca830110, /* lfd     f20,272(r3) */
+       0xcaa30118, /* lfd     f21,280(r3) */
+       0xcac30120, /* lfd     f22,288(r3) */
+       0xcae30128, /* lfd     f23,296(r3) */
+       0xcb030130, /* lfd     f24,304(r3) */
+       0xcb230138, /* lfd     f25,312(r3) */
+       0xcb430140, /* lfd     f26,320(r3) */
+       0xcb630148, /* lfd     f27,328(r3) */
+       0xcb830150, /* lfd     f28,336(r3) */
+       0xcba30158, /* lfd     f29,344(r3) */
+       0xcbc30160, /* lfd     f30,352(r3) */
+       0xcbe30168, /* lfd     f31,360(r3) */
+#endif
+
+#ifdef __ALTIVEC__
+       0x7ca042a6, /* mfvrsave r5 */
+       0x39040180, /* addi    r8,r4,384 */
+       0x39240190, /* addi    r9,r4,400 */
+       0x70a00fff, /* andi.   r0,r5,4095 */
+       0x90a40034, /* stw     r5,52(r4) */
+       0x4182005c, /* beq-    2 */
+       0x7e8041ce, /* stvx    v20,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7ea049ce, /* stvx    v21,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7ec041ce, /* stvx    v22,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7ee049ce, /* stvx    v23,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7f0041ce, /* stvx    v24,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7f2049ce, /* stvx    v25,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7f4041ce, /* stvx    v26,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7f6049ce, /* stvx    v27,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7f8041ce, /* stvx    v28,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7fa049ce, /* stvx    v29,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7fc041ce, /* stvx    v30,r0,r8 */
+       0x7fe049ce, /* stvx    v31,r0,r9 */
+       0x80a30034,/*2:lwz     r5,52(r3) */
+       0x39030180, /* addi    r8,r3,384 */
+       0x39230190, /* addi    r9,r3,400 */
+       0x70a00fff, /* andi.   r0,r5,4095 */
+       0x7ca043a6, /* mtvrsave r5 */
+       0x4d820420, /* beqctr   */
+       0x7e8040ce, /* lvx     v20,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7ea048ce, /* lvx     v21,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7ec040ce, /* lvx     v22,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7ee048ce, /* lvx     v23,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7f0040ce, /* lvx     v24,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7f2048ce, /* lvx     v25,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7f4040ce, /* lvx     v26,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7f6048ce, /* lvx     v27,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7f8040ce, /* lvx     v28,r0,r8 */
+       0x39080020, /* addi    r8,r8,32 */
+       0x7fa048ce, /* lvx     v29,r0,r9 */
+       0x39290020, /* addi    r9,r9,32 */
+       0x7fc040ce, /* lvx     v30,r0,r8 */
+       0x7fe048ce, /* lvx     v31,r0,r9 */
+#endif
+
+       0x4e800420, /* bctr */
+};
+
+       #if LIBCO_PPCDESC
+               /* Function call goes through indirect descriptor */
+               #define CO_SWAP_ASM(x, y) \
+                       ((void (*)(cothread_t, cothread_t)) (uintptr_t) x)(x, y)
+       #else
+               /* Function call goes directly to code */
+               #define CO_SWAP_ASM(x, y) \
+                       ((void (*)(cothread_t, cothread_t)) (uintptr_t) libco_ppc_code)(x, y)
+       #endif
+
+#endif
+
+static uint32_t* co_create_( unsigned size, uintptr_t entry)
+{
+       uint32_t *t = (uint32_t*)malloc(size);
+
+#if LIBCO_PPCDESC
+   if (t)
+   {
+      /* Copy entry's descriptor */
+      memcpy(t, (void*)entry, sizeof(void*) * 3);
+
+      /* Set function pointer to swap routine */
+#ifdef LIBCO_PPC_ASM
+      *(const void**) t = *(void**) &co_swap_asm;
+#else
+      *(const void**) t = libco_ppc_code;
+#endif
+   }
+       #endif
+
+       return t;
+}
+
+cothread_t co_create(unsigned int size, void (*entry_)(void))
+{
+       uintptr_t entry = (uintptr_t) entry_;
+       uint32_t *t     = NULL;
+
+       /* Be sure main thread was successfully allocated */
+       if (co_active())
+       {
+               size += state_size + above_stack + stack_align;
+               t     = co_create_(size, entry);
+       }
+
+       if (t)
+   {
+      uintptr_t sp;
+#if LIBCO_PPC64
+      int shift = 16;
+#else
+      int shift = 0;
+#endif
+      /* Save current registers into new thread, so that any special ones will
+         have proper values when thread is begun */
+      CO_SWAP_ASM(t, t);
+
+#if LIBCO_PPCDESC
+      /* Get real address */
+      entry     = (uintptr_t) *(void**)entry;
+#endif
+
+      /* Put stack near end of block, and align */
+      sp        = (uintptr_t) t + size - above_stack;
+      sp       -= sp % stack_align;
+
+      /* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
+         save and restore them as 64 bits, regardless of the size the ABI
+         uses. So, we manually write pointers at the proper size. We always
+         save and restore at the same address, and since PPC is big-endian,
+         we must put the low byte first on PPC32. */
+
+      /* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts
+         and don't have to care how many bits uintptr_t is. */
+
+      /* Set up so entry will be called on next swap */
+      t [8]  = (uint32_t) (entry >> shift >> shift);
+      t [9]  = (uint32_t) entry;
+
+      t [10] = (uint32_t) (sp    >> shift >> shift);
+      t [11] = (uint32_t) sp;
+   }
+
+       return t;
+}
+
+void co_delete(cothread_t t)
+{
+   free(t);
+}
+
+static void co_init_(void)
+{
+#if LIBCO_MPROTECT
+   /* TODO: pre- and post-pad PPC code so that this doesn't make other
+      data executable and writable */
+   long page_size = sysconf(_SC_PAGESIZE);
+   if (page_size > 0)
+   {
+      uintptr_t align = page_size;
+      uintptr_t begin = (uintptr_t) libco_ppc_code;
+      uintptr_t end   = begin + sizeof libco_ppc_code;
+
+      /* Align beginning and end */
+      end            += align - 1;
+      end            -= end   % align;
+      begin          -= begin % align;
+
+      mprotect((void*)begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC);
+   }
+#endif
+
+   co_active_handle = co_create_(state_size, (uintptr_t) &co_switch);
+}
+
+cothread_t co_active(void)
+{
+   if (!co_active_handle)
+      co_init_();
+
+   return co_active_handle;
+}
+
+void co_switch(cothread_t t)
+{
+   cothread_t old   = co_active_handle;
+   co_active_handle = t;
+   CO_SWAP_ASM(t, old);
+}
diff --git a/deps/libretro-common/libco/ps2.c b/deps/libretro-common/libco/ps2.c
new file mode 100644 (file)
index 0000000..78bc915
--- /dev/null
@@ -0,0 +1,59 @@
+#define LIBCO_C
+#include "libco.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <kernel.h>
+
+/* Since cothread_t is a void pointer it must contain an address. We can't return a reference to a local variable
+ * because it would go out of scope, so we create a static variable instead so we can return a reference to it.
+ */
+static int32_t active_thread_id = -1;
+extern void *_gp;
+
+cothread_t co_active()
+{
+  active_thread_id = GetThreadId();
+  return &active_thread_id;
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void))
+{
+   /* Similar scenario as with active_thread_id except there will only be one active_thread_id while there could be many
+    * new threads each with their own handle, so we create them on the heap instead and delete them manually when they're
+    * no longer needed in co_delete().
+    */
+   ee_thread_t thread;
+   int32_t new_thread_id;
+   cothread_t handle       = malloc(sizeof(cothread_t));
+   void *threadStack       = (void *)malloc(size);
+
+   if (!threadStack)
+      return -1;
+
+   thread.stack_size              = size;
+   thread.gp_reg                          = &_gp;
+   thread.func                            = (void *)entrypoint;
+   thread.stack                           = threadStack;
+   thread.option                          = 0;
+   thread.initial_priority = 1;
+
+   new_thread_id           = CreateThread(&thread);
+   StartThread(new_thread_id, NULL);
+   *(uint32_t *)handle     = new_thread_id;
+   return handle;
+}
+
+void co_delete(cothread_t handle)
+{
+   TerminateThread(*(uint32_t *)handle);
+   DeleteThread(*(uint32_t *)handle);
+   free(handle);
+}
+
+void co_switch(cothread_t handle)
+{
+   WakeupThread(*(uint32_t *)handle);
+   /* Sleep the currently active thread so the new thread can start */
+   SleepThread();
+}
diff --git a/deps/libretro-common/libco/ps3.S b/deps/libretro-common/libco/ps3.S
new file mode 100644 (file)
index 0000000..60a9134
--- /dev/null
@@ -0,0 +1,55 @@
+.globl .co_swap_asm
+.globl co_swap_asm
+.type .co_swap_asm, @function
+.type co_swap_asm, @function
+.co_swap_asm:
+co_swap_asm:
+      mfcr    8
+      std     1,40(4)
+      mflr    9
+      std     14,72(4)
+      std     15,80(4)
+      std     16,88(4)
+      std     17,96(4)
+      std     18,104(4)
+      std     19,112(4)
+      std     20,120(4)
+      std     21,128(4)
+      std     22,136(4)
+      std     23,144(4)
+      std     24,152(4)
+      std     25,160(4)
+      std     26,168(4)
+      std     27,176(4)
+      std     28,184(4)
+      std     29,192(4)
+      std     30,200(4)
+      std     31,208(4)
+      std     9,32(4)
+      ld      7,32(3)
+      ld      1,40(3)
+      bl      swap
+      trap
+swap: stw     8,48(4)
+      lwz     6,48(3)
+      mtctr   7
+      ld      14,72(3)
+      ld      15,80(3)
+      ld      16,88(3)
+      ld      17,96(3)
+      ld      18,104(3)
+      ld      19,112(3)
+      ld      20,120(3)
+      ld      21,128(3)
+      ld      22,136(3)
+      ld      23,144(3)
+      ld      24,152(3)
+      ld      25,160(3)
+      ld      26,168(3)
+      ld      27,176(3)
+      ld      28,184(3)
+      ld      29,192(3)
+      ld      30,200(3)
+      ld      31,208(3)
+      mtcr    6
+      bctr
diff --git a/deps/libretro-common/libco/psp1.c b/deps/libretro-common/libco/psp1.c
new file mode 100644 (file)
index 0000000..18914a2
--- /dev/null
@@ -0,0 +1,41 @@
+#define LIBCO_C
+#include "libco.h"
+
+#include <stdlib.h>
+#include <pspthreadman.h>
+
+typedef void (*entrypoint_t)(void);
+
+cothread_t co_active(void)
+{
+  return (void *)sceKernelGetThreadId();
+}
+
+static int thread_wrap(unsigned int argc, void *argp)
+{
+  entrypoint_t entrypoint = *(entrypoint_t *) argp;
+  sceKernelSleepThread();
+  entrypoint();
+  return 0;
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void))
+{
+  SceUID new_thread_id = sceKernelCreateThread("cothread", thread_wrap, 0x12, size, 0, NULL);
+  sceKernelStartThread(new_thread_id, sizeof (entrypoint), &entrypoint);
+  return (void *) new_thread_id;
+}
+
+void co_delete(cothread_t handle)
+{
+  SceUID id = (SceUID) handle;
+  sceKernelTerminateDeleteThread(id);
+}
+
+void co_switch(cothread_t handle)
+{
+  SceUID id = (SceUID) handle;
+  sceKernelWakeupThread(id);
+  /* Sleep the currently active thread so the new thread can start */
+  sceKernelSleepThread();
+}
diff --git a/deps/libretro-common/libco/psp2.c b/deps/libretro-common/libco/psp2.c
new file mode 100644 (file)
index 0000000..82271bd
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+libco.arm (2015-06-18)
+license: public domain
+*/
+
+#define LIBCO_C
+#include "libco.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <psp2/kernel/sysmem.h>
+#include <stdio.h>
+#include <string.h>
+
+#define FOUR_KB_ALIGN(x) align(x, 12)
+#define MB_ALIGN(x)      align(x, 20)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+   static inline int align(int x, int n)
+   {
+      return (((x >> n) + 1) << n);
+   }
+
+   static thread_local unsigned long co_active_buffer[64];
+   static thread_local cothread_t co_active_handle = 0;
+   static void(*co_swap)(cothread_t, cothread_t) = 0;
+   static int block;
+   static uint32_t co_swap_function[] = {
+      0xe8a16ff0,  /* stmia r1!, {r4-r11,sp,lr} */
+      0xe8b0aff0,  /* ldmia r0!, {r4-r11,sp,pc} */
+      0xe12fff1e,  /* bx lr                     */
+   };
+
+   static void co_init(void)
+   {
+      int ret;
+      void *base;
+
+      block = sceKernelAllocMemBlockForVM("libco",
+            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
+      if (block < 0)
+         return;
+
+      /* Get base address */
+      if ((ret = sceKernelGetMemBlockBase(block, &base)) < 0)
+         return;
+
+      /* Set domain to be writable by user */
+      if ((ret = sceKernelOpenVMDomain()) < 0)
+         return;
+
+      memcpy(base, co_swap_function, sizeof co_swap_function);
+
+      /* Set domain back to read-only */
+      if ((ret = sceKernelCloseVMDomain()) < 0)
+         return;
+
+      /* Flush icache */
+      ret = sceKernelSyncVMDomain(block, base,
+            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
+      if (ret < 0)
+         return;
+
+      co_swap = (void(*)(cothread_t, cothread_t))base;
+   }
+
+   cothread_t co_active(void)
+   {
+      if (!co_active_handle)
+         co_active_handle = &co_active_buffer;
+      return co_active_handle;
+   }
+
+   cothread_t co_create(unsigned int size, void(*entrypoint)(void))
+   {
+      unsigned long* handle = 0;
+      if (!co_swap)
+         co_init();
+      if (!co_active_handle)
+         co_active_handle   = &co_active_buffer;
+      size                 += 256;
+      size                 &= ~15;
+
+      if ((handle = (unsigned long*)malloc(size)))
+      {
+         unsigned long *p   = (unsigned long*)((unsigned char*)handle + size);
+         handle[8]          = (unsigned long)p;
+         handle[9]          = (unsigned long)entrypoint;
+      }
+
+      return handle;
+   }
+
+   void co_delete(cothread_t handle)
+   {
+      free(handle);
+      sceKernelFreeMemBlock(block);
+   }
+
+   void co_switch(cothread_t handle)
+   {
+      cothread_t co_previous_handle = co_active_handle;
+      co_swap(co_active_handle = handle, co_previous_handle);
+   }
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/scefiber.c b/deps/libretro-common/libco/scefiber.c
new file mode 100644 (file)
index 0000000..0a24073
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  libco.win (2016-09-06)
+  authors: frangarcj
+  license: public domain
+*/
+
+#define LIBCO_C
+#include <libco.h>
+#include <stdlib.h>
+#include <psp2/sysmodule.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local cothread_t co_active_ = 0;
+
+typedef struct SceFiber
+{
+       char reserved[128];
+} SceFiber __attribute__( ( aligned ( 8 ) ) ) ;
+
+/* Forward declarations */
+int32_t _sceFiberInitializeImpl(SceFiber *fiber, char *name, void *entry, uint32_t argOnInitialize,
+      void* addrContext, int32_t sizeContext, void* params);
+int32_t sceFiberFinalize(SceFiber* fiber);
+int32_t sceFiberRun(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
+int32_t sceFiberSwitch(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
+int32_t sceFiberReturnToThread(uint32_t argOnReturn, uint32_t* argOnRun);
+
+static void co_thunk(uint32_t argOnInitialize, uint32_t argOnRun)
+{
+   ((void (*)(void))argOnInitialize)();
+}
+
+cothread_t co_active(void)
+{
+   if (!co_active_)
+   {
+      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
+      co_active_ = (cothread_t)1;
+   }
+   return co_active_;
+}
+
+cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
+{
+   int ret;
+   SceFiber* tail_fiber   = malloc(sizeof(SceFiber));
+   char * m_ctxbuf        = malloc(sizeof(char)*heapsize);
+   if (!co_active_)
+   {
+      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
+      co_active_          = (cothread_t)1;
+   }
+
+   /* _sceFiberInitializeImpl */
+   if ((ret = _sceFiberInitializeImpl(
+               tail_fiber, "tailFiber", co_thunk,
+               (uint32_t)coentry, (void*)m_ctxbuf, heapsize, NULL)) == 0)
+      return (cothread_t)tail_fiber;
+   return (cothread_t)ret;
+}
+
+void co_delete(cothread_t cothread)
+{
+   if (cothread != (cothread_t)1)
+      sceFiberFinalize((SceFiber*)cothread);
+}
+
+void co_switch(cothread_t cothread)
+{
+   uint32_t argOnReturn  = 0;
+   if (cothread == (cothread_t)1)
+   {
+      co_active_         = cothread;
+      sceFiberReturnToThread(0, NULL);
+   }
+   else
+   {
+      SceFiber* theFiber = (SceFiber*)cothread;
+      co_active_         = cothread;
+      if (co_active_ == (cothread_t)1)
+         sceFiberRun(theFiber, 0, &argOnReturn);
+      else
+         sceFiberSwitch(theFiber, 0, &argOnReturn);
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/sjlj.c b/deps/libretro-common/libco/sjlj.c
new file mode 100644 (file)
index 0000000..c661d15
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+  libco.sjlj (2008-01-28)
+  author: Nach
+  license: public domain
+*/
+
+/*
+ * Note this was designed for UNIX systems. Based on ideas expressed in a paper
+ * by Ralf Engelschall.
+ * For SJLJ on other systems, one would want to rewrite springboard() and
+ * co_create() and hack the jmb_buf stack pointer.
+ */
+
+#define LIBCO_C
+#include <libco.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+   sigjmp_buf context;
+   void (*coentry)(void);
+   void *stack;
+} cothread_struct;
+
+static thread_local cothread_struct co_primary;
+static thread_local cothread_struct *creating, *co_running = 0;
+
+static void springboard(int ignored)
+{
+   if (sigsetjmp(creating->context, 0))
+      co_running->coentry();
+}
+
+cothread_t co_active(void)
+{
+  if (!co_running)
+     co_running = &co_primary;
+  return (cothread_t)co_running;
+}
+
+cothread_t co_create(unsigned int size, void (*coentry)(void))
+{
+   cothread_struct *thread;
+   if (!co_running)
+      co_running = &co_primary;
+
+   if ((thread = (cothread_struct*)malloc(sizeof(cothread_struct))))
+   {
+      stack_t stack;
+      stack_t old_stack;
+
+      thread->coentry = thread->stack = 0;
+
+      stack.ss_flags  = 0;
+      stack.ss_size   = size;
+      thread->stack   = stack.ss_sp = malloc(size);
+
+      if (stack.ss_sp && !sigaltstack(&stack, &old_stack))
+      {
+         struct sigaction old_handler = {{0}};
+         struct sigaction handler     = {{0}};
+         handler.sa_handler           = springboard;
+         handler.sa_flags             = SA_ONSTACK;
+         sigemptyset(&handler.sa_mask);
+         creating                     = thread;
+
+         if (!sigaction(SIGUSR1, &handler, &old_handler))
+         {
+            if (!raise(SIGUSR1))
+               thread->coentry        = coentry;
+            sigaltstack(&old_stack, 0);
+            sigaction(SIGUSR1, &old_handler, 0);
+         }
+      }
+
+      if (thread->coentry != coentry)
+      {
+         co_delete(thread);
+         thread = 0;
+      }
+   }
+
+   return (cothread_t)thread;
+}
+
+void co_delete(cothread_t cothread)
+{
+   if (cothread)
+   {
+      if (((cothread_struct*)cothread)->stack)
+         free(((cothread_struct*)cothread)->stack);
+      free(cothread);
+   }
+}
+
+void co_switch(cothread_t cothread)
+{
+   if (!sigsetjmp(co_running->context, 0))
+   {
+      co_running = (cothread_struct*)cothread;
+      siglongjmp(co_running->context, 1);
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/ucontext.c b/deps/libretro-common/libco/ucontext.c
new file mode 100644 (file)
index 0000000..949273d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+  libco.ucontext (2008-01-28)
+  author: Nach
+  license: public domain
+*/
+
+/*
+ * WARNING: the overhead of POSIX ucontext is very high,
+ * assembly versions of libco or libco_sjlj should be much faster
+ *
+ * This library only exists for two reasons:
+ * 1 - as an initial test for the viability of a ucontext implementation
+ * 2 - to demonstrate the power and speed of libco over existing implementations,
+ *     such as pth (which defaults to wrapping ucontext on unix targets)
+ *
+ * Use this library only as a *last resort*
+ */
+
+#define LIBCO_C
+#include <libco.h>
+#include <stdlib.h>
+#include <ucontext.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static thread_local ucontext_t co_primary;
+static thread_local ucontext_t *co_running = 0;
+
+cothread_t co_active(void)
+{
+   if (!co_running)
+      co_running = &co_primary;
+   return (cothread_t)co_running;
+}
+
+cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
+{
+   ucontext_t *thread;
+   if (!co_running)
+      co_running = &co_primary;
+
+   if ((thread = (ucontext_t*)malloc(sizeof(ucontext_t))))
+   {
+      if ((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize)))
+      {
+         thread->uc_link = co_running;
+         thread->uc_stack.ss_size = heapsize;
+         makecontext(thread, coentry, 0);
+      }
+      else
+      {
+         co_delete((cothread_t)thread);
+         thread = 0;
+      }
+   }
+   return (cothread_t)thread;
+}
+
+void co_delete(cothread_t cothread)
+{
+   if (!cothread)
+      return;
+
+   if (((ucontext_t*)cothread)->uc_stack.ss_sp)
+      free(((ucontext_t*)cothread)->uc_stack.ss_sp);
+   free(cothread);
+}
+
+void co_switch(cothread_t cothread)
+{
+   ucontext_t *old_thread = co_running;
+   co_running             = (ucontext_t*)cothread;
+   swapcontext(old_thread, co_running);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/libco/x86.c b/deps/libretro-common/libco/x86.c
new file mode 100644 (file)
index 0000000..24e5aa6
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+  libco.x86 (2009-10-12)
+  author: byuu
+  license: public domain
+*/
+
+#define LIBCO_C
+#include <libco.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_MSC_VER)
+  #define fastcall __fastcall
+#elif defined(__GNUC__)
+  #define fastcall __attribute__((fastcall))
+#else
+  #error "libco: please define fastcall macro"
+#endif
+
+static thread_local long co_active_buffer[64];
+static thread_local cothread_t co_active_handle = 0;
+static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
+
+//ABI: fastcall
+static unsigned char co_swap_function[] = {
+  0x89, 0x22,         /* mov [edx],esp      */
+  0x8b, 0x21,         /* mov esp,[ecx]      */
+  0x58,               /* pop eax            */
+  0x89, 0x6a, 0x04,   /* mov [edx+0x04],ebp */
+  0x89, 0x72, 0x08,   /* mov [edx+0x08],esi */
+  0x89, 0x7a, 0x0c,   /* mov [edx+0x0c],edi */
+  0x89, 0x5a, 0x10,   /* mov [edx+0x10],ebx */
+  0x8b, 0x69, 0x04,   /* mov ebp,[ecx+0x04] */
+  0x8b, 0x71, 0x08,   /* mov esi,[ecx+0x08] */
+  0x8b, 0x79, 0x0c,   /* mov edi,[ecx+0x0c] */
+  0x8b, 0x59, 0x10,   /* mov ebx,[ecx+0x10] */
+  0xff, 0xe0,         /* jmp eax            */
+};
+
+#ifdef _WIN32
+#include <windows.h>
+
+static void co_init(void)
+{
+   DWORD old_privileges;
+   VirtualProtect(co_swap_function,
+         sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
+}
+#else
+#include <unistd.h>
+#include <sys/mman.h>
+
+static void co_init(void)
+{
+   unsigned long addr = (unsigned long)co_swap_function;
+   unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
+   unsigned long size = (addr - base) + sizeof co_swap_function;
+   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
+}
+#endif
+
+static void crash(void)
+{
+   assert(0); /* called only if cothread_t entrypoint returns */
+}
+
+cothread_t co_active(void)
+{
+   if (!co_active_handle)
+      co_active_handle = &co_active_buffer;
+   return co_active_handle;
+}
+
+cothread_t co_create(unsigned int size, void (*entrypoint)(void))
+{
+   cothread_t handle;
+   if (!co_swap)
+   {
+      co_init();
+      co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
+   }
+
+   if (!co_active_handle)
+      co_active_handle = &co_active_buffer;
+
+   size += 256; /* allocate additional space for storage */
+   size &= ~15; /* align stack to 16-byte boundary */
+
+   if ((handle = (cothread_t)malloc(size)))
+   {
+      long *p        = (long*)((char*)handle + size); /* seek to top of stack */
+      *--p           = (long)crash;                   /* crash if entrypoint returns */
+      *--p           = (long)entrypoint;              /* start of function */
+      *(long*)handle = (long)p;                       /* stack pointer */
+   }
+
+   return handle;
+}
+
+void co_delete(cothread_t handle)
+{
+   free(handle);
+}
+
+void co_switch(cothread_t handle)
+{
+   register cothread_t co_previous_handle = co_active_handle;
+   co_swap(co_active_handle = handle, co_previous_handle);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/deps/libretro-common/lists/dir_list.c b/deps/libretro-common/lists/dir_list.c
new file mode 100644 (file)
index 0000000..e5e8182
--- /dev/null
@@ -0,0 +1,280 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (dir_list.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+
+#if defined(_WIN32) && defined(_XBOX)
+#include <xtl.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include <lists/dir_list.h>
+#include <lists/string_list.h>
+#include <file/file_path.h>
+
+#include <compat/strl.h>
+#include <retro_dirent.h>
+
+#include <string/stdstring.h>
+#include <retro_miscellaneous.h>
+
+static int qstrcmp_plain(const void *a_, const void *b_)
+{
+   const struct string_list_elem *a = (const struct string_list_elem*)a_;
+   const struct string_list_elem *b = (const struct string_list_elem*)b_;
+
+   return strcasecmp(a->data, b->data);
+}
+
+static int qstrcmp_dir(const void *a_, const void *b_)
+{
+   const struct string_list_elem *a = (const struct string_list_elem*)a_;
+   const struct string_list_elem *b = (const struct string_list_elem*)b_;
+   int a_type = a->attr.i;
+   int b_type = b->attr.i;
+
+   /* Sort directories before files. */
+   if (a_type != b_type)
+      return b_type - a_type;
+   return strcasecmp(a->data, b->data);
+}
+
+/**
+ * dir_list_sort:
+ * @list      : pointer to the directory listing.
+ * @dir_first : move the directories in the listing to the top?
+ *
+ * Sorts a directory listing.
+ **/
+void dir_list_sort(struct string_list *list, bool dir_first)
+{
+   if (list)
+      qsort(list->elems, list->size, sizeof(struct string_list_elem),
+            dir_first ? qstrcmp_dir : qstrcmp_plain);
+}
+
+/**
+ * dir_list_free:
+ * @list : pointer to the directory listing
+ *
+ * Frees a directory listing.
+ **/
+void dir_list_free(struct string_list *list)
+{
+   string_list_free(list);
+}
+
+bool dir_list_deinitialize(struct string_list *list)
+{
+   if (!list)
+      return false;
+   return string_list_deinitialize(list);
+}
+
+/**
+ * dir_list_read:
+ * @dir                : directory path.
+ * @list               : the string list to add files to
+ * @ext_list           : the string list of extensions to include
+ * @include_dirs       : include directories as part of the finished directory listing?
+ * @include_hidden     : include hidden files and directories as part of the finished directory listing?
+ * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
+ * @recursive          : list directory contents recursively
+ *
+ * Add files within a directory to an existing string list
+ *
+ * @return -1 on error, 0 on success.
+ **/
+static int dir_list_read(const char *dir,
+      struct string_list *list, struct string_list *ext_list,
+      bool include_dirs, bool include_hidden,
+      bool include_compressed, bool recursive)
+{
+   struct RDIR *entry = retro_opendir_include_hidden(dir, include_hidden);
+
+   if (!entry || retro_dirent_error(entry))
+      goto error;
+
+   while (retro_readdir(entry))
+   {
+      union string_list_elem_attr attr;
+      char file_path[PATH_MAX_LENGTH];
+      const char *name                = retro_dirent_get_name(entry);
+
+      if (name[0] == '.')
+      {
+         /* Do not include hidden files and directories */
+         if (!include_hidden)
+            continue;
+
+         /* char-wise comparisons to avoid string comparison */
+
+         /* Do not include current dir */
+         if (name[1] == '\0')
+            continue;
+         /* Do not include parent dir */
+         if (name[1] == '.' && name[2] == '\0')
+            continue;
+      }
+
+      fill_pathname_join_special(file_path, dir, name, sizeof(file_path));
+
+      if (retro_dirent_is_dir(entry, NULL))
+      {
+         if (recursive)
+            dir_list_read(file_path, list, ext_list, include_dirs,
+                  include_hidden, include_compressed, recursive);
+
+         if (!include_dirs)
+            continue;
+         attr.i = RARCH_DIRECTORY;
+      }
+      else
+      {
+         const char *file_ext    = path_get_extension(name);
+
+         attr.i                  = RARCH_FILETYPE_UNSET;
+
+         /*
+          * If the file format is explicitly supported by the libretro-core, we
+          * need to immediately load it and not designate it as a compressed file.
+          *
+          * Example: .zip could be supported as a image by the core and as a
+          * compressed_file. In that case, we have to interpret it as a image.
+          *
+          * */
+         if (string_list_find_elem_prefix(ext_list, ".", file_ext))
+            attr.i            = RARCH_PLAIN_FILE;
+         else
+         {
+            bool is_compressed_file;
+            if ((is_compressed_file = path_is_compressed_file(file_path)))
+               attr.i               = RARCH_COMPRESSED_ARCHIVE;
+
+            if (ext_list &&
+                  (!is_compressed_file || !include_compressed))
+               continue;
+         }
+      }
+
+      if (!string_list_append(list, file_path, attr))
+         goto error;
+   }
+
+   retro_closedir(entry);
+
+   return 0;
+
+error:
+   if (entry)
+      retro_closedir(entry);
+   return -1;
+}
+
+/**
+ * dir_list_append:
+ * @list               : existing list to append to.
+ * @dir                : directory path.
+ * @ext                : allowed extensions of file directory entries to include.
+ * @include_dirs       : include directories as part of the finished directory listing?
+ * @include_hidden     : include hidden files and directories as part of the finished directory listing?
+ * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
+ * @recursive          : list directory contents recursively
+ *
+ * Create a directory listing, appending to an existing list
+ *
+ * @return Returns true on success, otherwise false.
+ **/
+bool dir_list_append(struct string_list *list,
+      const char *dir,
+      const char *ext, bool include_dirs,
+      bool include_hidden, bool include_compressed,
+      bool recursive)
+{
+   bool ret                         = false;
+   struct string_list ext_list      = {0};
+   struct string_list *ext_list_ptr = NULL;
+
+   if (ext)
+   {
+      string_list_initialize(&ext_list);
+      string_split_noalloc(&ext_list, ext, "|");
+      ext_list_ptr                  = &ext_list;
+   }
+   ret                            = dir_list_read(dir, list, ext_list_ptr,
+         include_dirs, include_hidden, include_compressed, recursive) != -1;
+   string_list_deinitialize(&ext_list);
+   return ret;
+}
+
+/**
+ * dir_list_new:
+ * @dir                : directory path.
+ * @ext                : allowed extensions of file directory entries to include.
+ * @include_dirs       : include directories as part of the finished directory listing?
+ * @include_hidden     : include hidden files and directories as part of the finished directory listing?
+ * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.
+ * @recursive          : list directory contents recursively
+ *
+ * Create a directory listing.
+ *
+ * @return pointer to a directory listing of type 'struct string_list *' on success,
+ * NULL in case of error. Has to be freed manually.
+ **/
+struct string_list *dir_list_new(const char *dir,
+      const char *ext, bool include_dirs,
+      bool include_hidden, bool include_compressed,
+      bool recursive)
+{
+   struct string_list *list       = string_list_new();
+
+   if (!list)
+      return NULL;
+
+   if (!dir_list_append(list, dir, ext, include_dirs,
+            include_hidden, include_compressed, recursive))
+   {
+      string_list_free(list);
+      return NULL;
+   }
+
+   return list;
+}
+
+/**
+ * dir_list_initialize:
+ *
+ * NOTE: @list must zero initialised before
+ * calling this function, otherwise UB.
+ **/
+bool dir_list_initialize(struct string_list *list,
+      const char *dir,
+      const char *ext, bool include_dirs,
+      bool include_hidden, bool include_compressed,
+      bool recursive)
+{
+   if (list && string_list_initialize(list))
+      return dir_list_append(list, dir, ext, include_dirs,
+            include_hidden, include_compressed, recursive);
+   return false;
+}
diff --git a/deps/libretro-common/lists/file_list.c b/deps/libretro-common/lists/file_list.c
new file mode 100644 (file)
index 0000000..e7a4e9c
--- /dev/null
@@ -0,0 +1,353 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_list.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <retro_common.h>
+#include <lists/file_list.h>
+#include <string/stdstring.h>
+#include <compat/strcasestr.h>
+
+static bool file_list_deinitialize_internal(file_list_t *list)
+{
+   size_t i;
+   for (i = 0; i < list->size; i++)
+   {
+      file_list_free_userdata(list, i);
+      file_list_free_actiondata(list, i);
+
+      if (list->list[i].path)
+         free(list->list[i].path);
+      list->list[i].path = NULL;
+
+      if (list->list[i].label)
+         free(list->list[i].label);
+      list->list[i].label = NULL;
+
+      if (list->list[i].alt)
+         free(list->list[i].alt);
+      list->list[i].alt = NULL;
+   }
+   if (list->list)
+      free(list->list);
+   list->list = NULL;
+   return true;
+}
+
+bool file_list_reserve(file_list_t *list, size_t nitems)
+{
+   const size_t item_size = sizeof(struct item_file);
+   struct item_file *new_data;
+
+   if (nitems < list->capacity || nitems > (size_t)-1/item_size)
+      return false;
+
+   if (!(new_data = (struct item_file*)realloc(list->list, nitems * item_size)))
+      return false;
+
+   memset(&new_data[list->capacity], 0, item_size * (nitems - list->capacity));
+
+   list->list     = new_data;
+   list->capacity = nitems;
+
+   return true;
+}
+
+bool file_list_insert(file_list_t *list,
+      const char *path, const char *label,
+      unsigned type, size_t directory_ptr,
+      size_t entry_idx,
+      size_t idx)
+{
+   int i;
+
+   /* Expand file list if needed */
+   if (list->size >= list->capacity)
+      if (!file_list_reserve(list, list->capacity * 2 + 1))
+         return false;
+
+   for (i = (unsigned)list->size; i > (int)idx; i--)
+   {
+      struct item_file *copy = (struct item_file*)
+         malloc(sizeof(struct item_file));
+
+      copy->path             = NULL;
+      copy->label            = NULL;
+      copy->alt              = NULL;
+      copy->type             = 0;
+      copy->directory_ptr    = 0;
+      copy->entry_idx        = 0;
+      copy->userdata         = NULL;
+      copy->actiondata       = NULL;
+
+      memcpy(copy, &list->list[i-1], sizeof(struct item_file));
+
+      memcpy(&list->list[i-1], &list->list[i], sizeof(struct item_file));
+      memcpy(&list->list[i],             copy, sizeof(struct item_file));
+
+      free(copy);
+   }
+
+   list->list[idx].path          = NULL;
+   list->list[idx].label         = NULL;
+   list->list[idx].alt           = NULL;
+   list->list[idx].type          = type;
+   list->list[idx].directory_ptr = directory_ptr;
+   list->list[idx].entry_idx     = entry_idx;
+   list->list[idx].userdata      = NULL;
+   list->list[idx].actiondata    = NULL;
+
+   if (label)
+      list->list[idx].label      = strdup(label);
+   if (path)
+      list->list[idx].path       = strdup(path);
+
+   list->size++;
+
+   return true;
+}
+
+bool file_list_append(file_list_t *list,
+      const char *path, const char *label,
+      unsigned type, size_t directory_ptr,
+      size_t entry_idx)
+{
+   unsigned idx = (unsigned)list->size;
+   /* Expand file list if needed */
+   if (idx >= list->capacity)
+      if (!file_list_reserve(list, list->capacity * 2 + 1))
+         return false;
+
+   list->list[idx].path          = NULL;
+   list->list[idx].label         = NULL;
+   list->list[idx].alt           = NULL;
+   list->list[idx].type          = type;
+   list->list[idx].directory_ptr = directory_ptr;
+   list->list[idx].entry_idx     = entry_idx;
+   list->list[idx].userdata      = NULL;
+   list->list[idx].actiondata    = NULL;
+
+   if (label)
+      list->list[idx].label      = strdup(label);
+   if (path)
+      list->list[idx].path       = strdup(path);
+
+   list->size++;
+
+   return true;
+}
+
+void file_list_pop(file_list_t *list, size_t *directory_ptr)
+{
+   if (!list)
+      return;
+
+   if (list->size != 0)
+   {
+      --list->size;
+      if (list->list[list->size].path)
+         free(list->list[list->size].path);
+      list->list[list->size].path = NULL;
+
+      if (list->list[list->size].label)
+         free(list->list[list->size].label);
+      list->list[list->size].label = NULL;
+   }
+
+   if (directory_ptr)
+      *directory_ptr = list->list[list->size].directory_ptr;
+}
+
+void file_list_free(file_list_t *list)
+{
+   if (!list)
+      return;
+   file_list_deinitialize_internal(list);
+   free(list);
+}
+
+bool file_list_deinitialize(file_list_t *list)
+{
+   if (!list)
+      return false;
+   if (!file_list_deinitialize_internal(list))
+      return false;
+   list->capacity = 0;
+   list->size     = 0;
+   return true;
+}
+
+void file_list_clear(file_list_t *list)
+{
+   size_t i;
+
+   if (!list)
+      return;
+
+   for (i = 0; i < list->size; i++)
+   {
+      if (list->list[i].path)
+         free(list->list[i].path);
+      list->list[i].path = NULL;
+
+      if (list->list[i].label)
+         free(list->list[i].label);
+      list->list[i].label = NULL;
+
+      if (list->list[i].alt)
+         free(list->list[i].alt);
+      list->list[i].alt = NULL;
+   }
+
+   list->size = 0;
+}
+
+static void file_list_get_label_at_offset(const file_list_t *list, size_t idx,
+      const char **label)
+{
+   if (!label || !list)
+      return;
+
+   *label = list->list[idx].path;
+   if (list->list[idx].label)
+      *label = list->list[idx].label;
+}
+
+void file_list_set_alt_at_offset(file_list_t *list, size_t idx,
+      const char *alt)
+{
+   if (!list || !alt)
+      return;
+
+   if (list->list[idx].alt)
+      free(list->list[idx].alt);
+   list->list[idx].alt      = NULL;
+
+   if (alt)
+      list->list[idx].alt   = strdup(alt);
+}
+
+static int file_list_alt_cmp(const void *a_, const void *b_)
+{
+   const struct item_file *a = (const struct item_file*)a_;
+   const struct item_file *b = (const struct item_file*)b_;
+   const char *cmp_a         = a->alt ? a->alt : a->path;
+   const char *cmp_b         = b->alt ? b->alt : b->path;
+   return strcasecmp(cmp_a, cmp_b);
+}
+
+static int file_list_type_cmp(const void *a_, const void *b_)
+{
+   const struct item_file *a = (const struct item_file*)a_;
+   const struct item_file *b = (const struct item_file*)b_;
+   if (a->type < b->type)
+      return -1;
+   if (a->type == b->type)
+      return 0;
+
+   return 1;
+}
+
+void file_list_sort_on_alt(file_list_t *list)
+{
+   qsort(list->list, list->size, sizeof(list->list[0]), file_list_alt_cmp);
+}
+
+void file_list_sort_on_type(file_list_t *list)
+{
+   qsort(list->list, list->size, sizeof(list->list[0]), file_list_type_cmp);
+}
+
+void *file_list_get_userdata_at_offset(const file_list_t *list, size_t idx)
+{
+   if (!list)
+      return NULL;
+   return list->list[idx].userdata;
+}
+
+void *file_list_get_actiondata_at_offset(const file_list_t *list, size_t idx)
+{
+   if (!list)
+      return NULL;
+   return list->list[idx].actiondata;
+}
+
+void file_list_free_actiondata(const file_list_t *list, size_t idx)
+{
+   if (!list)
+      return;
+   if (list->list[idx].actiondata)
+       free(list->list[idx].actiondata);
+   list->list[idx].actiondata = NULL;
+}
+
+void file_list_free_userdata(const file_list_t *list, size_t idx)
+{
+   if (!list)
+      return;
+   if (list->list[idx].userdata)
+       free(list->list[idx].userdata);
+   list->list[idx].userdata = NULL;
+}
+
+bool file_list_search(const file_list_t *list, const char *needle, size_t *idx)
+{
+   size_t i;
+   bool ret        = false;
+
+   if (!list)
+      return false;
+
+   for (i = 0; i < list->size; i++)
+   {
+      const char *str = NULL;
+      const char *alt = list->list[i].alt 
+            ? list->list[i].alt 
+            : list->list[i].path;
+
+      if (!alt)
+      {
+         file_list_get_label_at_offset(list, i, &alt);
+         if (!alt)
+            continue;
+      }
+
+      if ((str = (const char *)strcasestr(alt, needle)) == alt)
+      {
+         /* Found match with first chars, best possible match. */
+         *idx = i;
+         ret  = true;
+         break;
+      }
+      else if (str && !ret)
+      {
+         /* Found mid-string match, but try to find a match with
+          * first characters before we settle. */
+         *idx = i;
+         ret  = true;
+      }
+   }
+
+   return ret;
+}
diff --git a/deps/libretro-common/lists/linked_list.c b/deps/libretro-common/lists/linked_list.c
new file mode 100644 (file)
index 0000000..fce754d
--- /dev/null
@@ -0,0 +1,479 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (linked_list.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <boolean.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <lists/linked_list.h>
+
+struct linked_list_item_t
+{
+   void *value;
+   struct linked_list_item_t *previous;
+   struct linked_list_item_t *next;
+};
+
+struct linked_list
+{
+   struct linked_list_item_t *first_item;
+   struct linked_list_item_t *last_item;
+   size_t length;
+};
+
+struct linked_list_iterator
+{
+   linked_list_t *list;
+   struct linked_list_item_t *item;
+   bool forward;
+};
+
+linked_list_t *linked_list_new(void)
+{
+   linked_list_t *list;
+
+   list = (linked_list_t *)calloc(sizeof(linked_list_t), 1);
+   return list;
+}
+
+void linked_list_free(linked_list_t *list, void (*free_value)(void *value))
+{
+   if (!list)
+   {
+      return;
+   }
+
+   while (list->first_item)
+   {
+      struct linked_list_item_t *next;
+
+      next = list->first_item->next;
+      if (free_value)
+         free_value(list->first_item->value);
+      free(list->first_item);
+
+      list->first_item = next;
+   }
+
+   free (list);
+}
+
+void linked_list_add(linked_list_t *list, void *value)
+{
+   struct linked_list_item_t *new_item;
+
+   if (!list)
+      return;
+
+   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));
+   new_item->value = value;
+   new_item->previous = list->last_item;
+   new_item->next = NULL;
+
+   if (list->length == 0)
+      list->first_item = new_item;
+   else
+      list->last_item->next = new_item;
+
+   list->last_item = new_item;
+   list->length++;
+}
+
+void linked_list_insert(linked_list_t *list, size_t index, void *value)
+{
+   size_t i;
+   struct linked_list_item_t *previous_item;
+   struct linked_list_item_t *next_item;
+   struct linked_list_item_t *new_item;
+
+   if (!list || index > list->length)
+      return;
+
+   previous_item = NULL;
+   next_item = list->first_item;
+   for (i = 1; i <= index; i++)
+   {
+      previous_item = next_item;
+      next_item = next_item->next;
+   }
+
+   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));
+   new_item->value = value;
+
+   if (previous_item)
+      previous_item->next = new_item;
+   else
+      list->first_item = new_item;
+   new_item->previous = previous_item;
+
+   if (next_item)
+      next_item->previous = new_item;
+   else
+      list->last_item = new_item;
+   new_item->next = next_item;
+
+   list->length++;
+}
+
+void *linked_list_get(linked_list_t *list, size_t index)
+{
+   size_t i;
+   struct linked_list_item_t *item;
+
+   if (!list)
+      return NULL;
+
+   if (index >= list->length)
+      return NULL;
+
+   item = list->first_item;
+   for (i = 1; i <= index; i++)
+      item = item->next;
+
+   return item->value;
+}
+
+void *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)
+{
+   struct linked_list_item_t *item;
+
+   if (!list || !matches)
+      return NULL;
+
+   for (item = list->first_item; item; item = item->next)
+   {
+      if (matches(item->value, usrptr))
+         return item->value;
+   }
+
+   return NULL;
+}
+
+void *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)
+{
+   struct linked_list_item_t *item;
+
+   if (!list || !matches)
+      return NULL;
+
+   for (item = list->last_item; item; item = item->previous)
+   {
+      if (matches(item->value, usrptr))
+         return item->value;
+   }
+
+   return NULL;
+}
+
+static void _linked_list_remove_item(linked_list_t *list, struct linked_list_item_t *item)
+{
+   struct linked_list_item_t *previous_item;
+   struct linked_list_item_t *next_item;
+
+   previous_item = item->previous;
+   next_item = item->next;
+   free(item);
+   list->length--;
+
+   if (previous_item)
+      previous_item->next = next_item;
+   else
+      list->first_item = next_item;
+
+   if (next_item)
+      next_item->previous = previous_item;
+   else
+      list->last_item = previous_item;
+}
+
+void *linked_list_remove_at(linked_list_t *list, size_t index)
+{
+   size_t i = 0;
+   struct linked_list_item_t *item;
+   void *value;
+
+   if (!list || list->length == 0 || index >= list->length)
+      return NULL;
+
+   item = list->first_item;
+   for (i = 1; i <= index; i++)
+      item = item->next;
+
+   value = item->value;
+   _linked_list_remove_item(list, item);
+   return value;
+}
+
+void *linked_list_remove_first(linked_list_t *list, void *value)
+{
+   struct linked_list_item_t *item;
+
+   if (!list)
+      return NULL;
+
+   for (item = list->first_item; item; item = item->next)
+   {
+      if (item->value == value)
+         break;
+   }
+
+   if (item)
+   {
+      _linked_list_remove_item(list, item);
+      return value;
+   }
+
+   return NULL;
+}
+
+void *linked_list_remove_last(linked_list_t *list, void *value)
+{
+   struct linked_list_item_t *item;
+
+   if (!list)
+      return NULL;
+
+   for (item = list->last_item; item; item = item->previous)
+   {
+      if (item->value == value)
+         break;
+   }
+
+   if (item)
+   {
+      _linked_list_remove_item(list, item);
+      return value;
+   }
+
+   return NULL;
+}
+
+void *linked_list_remove_all(linked_list_t *list, void *value)
+{
+   struct linked_list_item_t *item;
+   bool found = false;
+
+   if (!list)
+      return NULL;
+
+   for (item = list->first_item; item;)
+   {
+      if (item->value == value)
+      {
+         struct linked_list_item_t *next_item;
+
+         next_item = item->next;
+         _linked_list_remove_item(list, item);
+         found = true;
+         item = next_item;
+      } else
+      {
+         item = item->next;
+      }
+   }
+
+   return found ? value : NULL;
+}
+
+void *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value))
+{
+   struct linked_list_item_t *item;
+
+   if (!list)
+      return NULL;
+
+   for (item = list->first_item; item; item = item->next)
+   {
+      if (matches(item->value))
+         break;
+   }
+
+   if (item)
+   {
+      void *value;
+
+      value = item->value;
+      _linked_list_remove_item(list, item);
+      return value;
+   }
+
+   return NULL;
+}
+
+void *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value))
+{
+   struct linked_list_item_t *item;
+
+   if (!list)
+      return NULL;
+
+   for (item = list->last_item; item; item = item->previous)
+   {
+      if (matches(item->value))
+         break;
+   }
+
+   if (item)
+   {
+      void *value;
+
+      value = item->value;
+      _linked_list_remove_item(list, item);
+      return value;
+   }
+
+   return NULL;
+}
+
+void linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value))
+{
+   struct linked_list_item_t *item;
+
+   if (!list)
+      return;
+
+   for (item = list->first_item; item;)
+   {
+      if (matches(item->value))
+      {
+         struct linked_list_item_t *next_item;
+
+         next_item = item->next;
+         _linked_list_remove_item(list, item);
+         item = next_item;
+      } else
+      {
+         item = item->next;
+      }
+   }
+}
+
+bool linked_list_set_at(linked_list_t *list, size_t index, void *value)
+{
+   struct linked_list_item_t *item;
+   size_t i;
+
+   if (!list || list->length == 0 || index >= list->length)
+      return false;
+
+   item = list->first_item;
+   for (i = 1; i <= index; i++)
+      item = item->next;
+
+   if (item)
+   {
+      item->value = value;
+      return true;
+   }
+
+   return false;
+}
+
+size_t linked_list_size(linked_list_t *list)
+{
+   if (list)
+      return list->length;
+
+   return 0;
+}
+
+linked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward)
+{
+   linked_list_iterator_t *iterator;
+
+   if (!list || !list->first_item)
+      return NULL;
+
+   iterator = (linked_list_iterator_t *)malloc(sizeof(linked_list_iterator_t));
+   iterator->list = list;
+   iterator->item = forward ? list->first_item : list->last_item;
+   iterator->forward = forward;
+
+   return iterator;
+}
+
+linked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator)
+{
+   struct linked_list_item_t *item;
+
+   if (!iterator)
+      return NULL;
+
+   item = iterator->forward ? iterator->item->next : iterator->item->previous;
+   if (item)
+   {
+      iterator->item = item;
+      return iterator;
+   } else
+   {
+      free(iterator);
+      return NULL;
+   }
+}
+
+void *linked_list_iterator_value(linked_list_iterator_t *iterator)
+{
+   if (iterator)
+      return iterator->item->value;
+
+   return NULL;
+}
+
+linked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator)
+{
+   struct linked_list_item_t *next_item;
+
+   if (!iterator)
+      return NULL;
+
+   next_item = iterator->forward ? iterator->item->next : iterator->item->previous;
+   _linked_list_remove_item(iterator->list, iterator->item);
+
+   if (next_item)
+   {
+      iterator->item = next_item;
+      return iterator;
+   } else
+   {
+      free(iterator);
+      return NULL;
+   }
+}
+
+void linked_list_iterator_free(linked_list_iterator_t *iterator)
+{
+   if (iterator)
+      free(iterator);
+}
+
+void linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value))
+{
+   size_t i;
+   struct linked_list_item_t *item;
+
+   if (!list || !fn)
+      return;
+
+   i = 0;
+   for (item = list->first_item; item; item = item->next)
+      fn(i++, item->value);
+}
diff --git a/deps/libretro-common/lists/nested_list.c b/deps/libretro-common/lists/nested_list.c
new file mode 100644 (file)
index 0000000..a57858c
--- /dev/null
@@ -0,0 +1,613 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (nested_list.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <string/stdstring.h>
+#include <lists/string_list.h>
+#include <array/rbuf.h>
+#include <array/rhmap.h>
+
+#include <lists/nested_list.h>
+
+struct nested_list_item
+{
+   nested_list_item_t *parent_item;
+   nested_list_t *parent_list;
+   nested_list_t *children;
+   char *id;
+   const void *value;
+};
+
+struct nested_list
+{
+   nested_list_item_t **items;
+   nested_list_item_t **item_map;
+};
+
+/**************************************/
+/* Initialisation / De-Initialisation */
+/**************************************/
+
+/* Forward declaration - required since
+ * nested_list_free_list() is recursive */
+static void nested_list_free_list(nested_list_t *list);
+
+/* Frees contents of a nested list item */
+static void nested_list_free_item(nested_list_item_t *item)
+{
+   if (!item)
+      return;
+
+   item->parent_item = NULL;
+   item->parent_list = NULL;
+
+   if (item->children)
+   {
+      nested_list_free_list(item->children);
+      item->children = NULL;
+   }
+
+   if (item->id)
+   {
+      free(item->id);
+      item->id = NULL;
+   }
+
+   item->value = NULL;
+   free(item);
+}
+
+/* Frees contents of a nested list */
+static void nested_list_free_list(nested_list_t *list)
+{
+   size_t i;
+
+   if (!list)
+      return;
+
+   for (i = 0; i < RBUF_LEN(list->items); i++)
+      nested_list_free_item(list->items[i]);
+
+   RBUF_FREE(list->items);
+   RHMAP_FREE(list->item_map);
+   free(list);
+}
+
+/**
+ * nested_list_init:
+ *
+ * Creates a new empty nested list. Returned pointer
+ * must be freed using nested_list_free.
+ *
+ * Returns: Valid nested_list_t pointer if successful,
+ * otherwise NULL.
+ */
+nested_list_t *nested_list_init(void)
+{
+   /* Create nested list */
+   nested_list_t *list = (nested_list_t*)malloc(sizeof(*list));
+
+   if (!list)
+      return NULL;
+
+   /* Initialise members */
+   list->items    = NULL;
+   list->item_map = NULL;
+
+   return list;
+}
+
+/**
+ * nested_list_free:
+ * @list : pointer to nested_list_t object
+ *
+ * Frees specified nested list.
+ */
+void nested_list_free(nested_list_t *list)
+{
+   nested_list_free_list(list);
+}
+
+/***********/
+/* Setters */
+/***********/
+
+/* Creates and adds a new item to the specified
+ * nested list. Returns NULL if item matching 'id'
+ * already exists */
+static nested_list_item_t *nested_list_add_item_to_list(nested_list_t *list,
+      nested_list_item_t *parent_item, const char *id, const void *value)
+{
+   size_t num_items             = 0;
+   nested_list_item_t *new_item = NULL;
+   nested_list_t *child_list    = NULL;
+
+   if (!list || string_is_empty(id))
+      goto end;
+
+   num_items = RBUF_LEN(list->items);
+
+   /* Ensure that item does not already exist */
+   if (RHMAP_HAS_STR(list->item_map, id))
+      goto end;
+
+   /* Attempt to allocate a buffer slot for the
+    * new item */
+   if (!RBUF_TRYFIT(list->items, num_items + 1))
+      goto end;
+
+   /* Create new empty child list */
+   child_list = nested_list_init();
+   if (!child_list)
+      goto end;
+
+   /* Create new list item */
+   new_item = (nested_list_item_t*)malloc(sizeof(*new_item));
+   if (!new_item)
+   {
+      nested_list_free(child_list);
+      goto end;
+   }
+
+   /* Assign members */
+   new_item->parent_item = parent_item;
+   new_item->parent_list = list;
+   new_item->children    = child_list;
+   new_item->id          = strdup(id);
+   new_item->value       = value;
+
+   /* Increment item buffer size */
+   RBUF_RESIZE(list->items, num_items + 1);
+
+   /* Add new item to buffer */
+   list->items[num_items] = new_item;
+
+   /* Update map */
+   RHMAP_SET_STR(list->item_map, id, new_item);
+end:
+   return new_item;
+}
+
+/**
+ * nested_list_add_item:
+ *
+ * @list    : pointer to nested_list_t object
+ * @address : a delimited list of item identifiers,
+ *            corresponding to item 'levels'
+ * @delim   : delimiter to use when splitting @address
+ *            into individual ids
+ * @value   : optional value (user data) associated with
+ *            new list item. This is added to the last
+ *            item specified by @address
+ *
+ * Appends a new item to the specified nested list.
+ * If @delim is NULL, item is added to the top level
+ * list (@list itself) with id equal to @address.
+ * Otherwise, @address is split by @delim and each
+ * id is added as new 'layer'. For example:
+ *
+ * > @address = "one:two:three", @delim = ":" will
+ *   produce:
+ *      top_level_list:one
+ *                     `- "one" list:two
+ *                                   `- "two" list:three
+ *   where @value is assigned to the "two" list:three
+ *   item.
+ *
+ * Returns: true if successful, otherwise false. Will
+ * always return false if item specified by @address
+ * already exists in the nested list.
+ */
+bool nested_list_add_item(nested_list_t *list,
+      const char *address, const char *delim, const void *value)
+{
+   struct string_list id_list = {0};
+   const char *top_id         = NULL;
+   bool success               = false;
+
+   if (!list || string_is_empty(address))
+      goto end;
+
+   /* If delim is NULL or address contains a single
+    * token, then we are adding an item to the top
+    * level list */
+   if (string_is_empty(delim))
+      top_id = address;
+   else
+   {
+      string_list_initialize(&id_list);
+      if (!string_split_noalloc(&id_list, address, delim) ||
+          (id_list.size < 1))
+         goto end;
+
+      if (id_list.size == 1)
+         top_id = id_list.elems[0].data;
+   }
+
+   if (!string_is_empty(top_id))
+   {
+      if (nested_list_add_item_to_list(list, NULL, top_id, value))
+         success = true;
+   }
+   else
+   {
+      nested_list_t *current_list     = list;
+      nested_list_item_t *parent_item = NULL;
+      nested_list_item_t *next_item   = NULL;
+      size_t i;
+
+      /* Loop over list item ids */
+      for (i = 0; i < id_list.size; i++)
+      {
+         const char *id = id_list.elems[i].data;
+
+         if (string_is_empty(id))
+            goto end;
+
+         /* If this is the last entry in the id list,
+          * then we are adding the item itself */
+         if (i == (id_list.size - 1))
+         {
+            if (nested_list_add_item_to_list(current_list,
+                  parent_item, id, value))
+               success = true;
+
+            break;
+         }
+         /* Otherwise, id corresponds to a 'category' */
+         else
+         {
+            /* Check whether category item already exists */
+            next_item = RHMAP_GET_STR(current_list->item_map, id);
+
+            /* Create it, if required */
+            if (!next_item)
+               next_item = nested_list_add_item_to_list(current_list,
+                     parent_item, id, NULL);
+
+            if (!next_item)
+               break;
+
+            /* Update pointers */
+            parent_item  = next_item;
+            current_list = next_item->children;
+         }
+      }
+   }
+
+end:
+   string_list_deinitialize(&id_list);
+   return success;
+}
+
+/***********/
+/* Getters */
+/***********/
+
+/**
+ * nested_list_get_size:
+ *
+ * @list : pointer to nested_list_t object
+ *
+ * Fetches the current size (number of items) in
+ * the specified list.
+ *
+ * Returns: list size.
+ */
+size_t nested_list_get_size(nested_list_t *list)
+{
+   if (!list)
+      return 0;
+
+   return RBUF_LEN(list->items);
+}
+
+/**
+ * nested_list_get_item:
+ *
+ * @list    : pointer to nested_list_t object
+ * @address : a delimited list of item identifiers,
+ *            corresponding to item 'levels'
+ * @delim   : delimiter to use when splitting @address
+ *            into individual ids
+ *
+ * Searches for (and returns) the list item corresponding
+ * to @address. If @delim is NULL, the top level list
+ * (@list itself) is searched for an item with an id
+ * equal to @address. Otherwise, @address is split by
+ * @delim and each id is searched for in a subsequent
+ * list level.
+ *
+ * Returns: valid nested_list_item_t pointer if item
+ * is found, otherwise NULL.
+ */
+nested_list_item_t *nested_list_get_item(nested_list_t *list,
+      const char *address, const char *delim)
+{
+   nested_list_item_t *search_item = NULL;
+   struct string_list id_list      = {0};
+   const char *top_id              = NULL;
+
+   if (!list || string_is_empty(address))
+      goto end;
+
+   /* If delim is NULL or address contains a single
+    * token, then we are fetching an item from the
+    * top level list */
+   if (string_is_empty(delim))
+      top_id = address;
+   else
+   {
+      string_list_initialize(&id_list);
+      if (!string_split_noalloc(&id_list, address, delim) ||
+          (id_list.size < 1))
+         goto end;
+
+      if (id_list.size == 1)
+         top_id = id_list.elems[0].data;
+   }
+
+   if (!string_is_empty(top_id))
+      search_item = RHMAP_GET_STR(list->item_map, top_id);
+   else
+   {
+      /* Otherwise, search 'category' levels */
+      nested_list_t *current_list   = list;
+      nested_list_item_t *next_item = NULL;
+      size_t i;
+
+      /* Loop over list item ids */
+      for (i = 0; i < id_list.size; i++)
+      {
+         const char *id = id_list.elems[i].data;
+
+         if (string_is_empty(id))
+            goto end;
+
+         /* If this is the last entry in the id list,
+          * then we are searching for the item itself */
+         if (i == (id_list.size - 1))
+         {
+            search_item = RHMAP_GET_STR(current_list->item_map, id);
+            break;
+         }
+         /* Otherwise, id corresponds to a 'category' */
+         else
+         {
+            next_item = RHMAP_GET_STR(current_list->item_map, id);
+
+            if (!next_item)
+               break;
+
+            /* Update pointer */
+            current_list = next_item->children;
+         }
+      }
+   }
+
+end:
+   string_list_deinitialize(&id_list);
+   return search_item;
+}
+
+/**
+ * nested_list_get_item_idx:
+ *
+ * @list : pointer to nested_list_t object
+ * @idx  : item index
+ *
+ * Fetches the item corresponding to index @idx in
+ * the top level list (@list itself) of the specified
+ * nested list.
+ *
+ * Returns: valid nested_list_item_t pointer if item
+ * exists, otherwise NULL.
+ */
+nested_list_item_t *nested_list_get_item_idx(nested_list_t *list,
+      size_t idx)
+{
+   if (!list || (idx >= RBUF_LEN(list->items)))
+      return NULL;
+
+   return list->items[idx];
+}
+
+/**
+ * nested_list_item_get_parent:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches the parent item of the specified nested
+ * list item. If returned value is NULL, specified
+ * nested list item belongs to a top level list.
+ *
+ * Returns: valid nested_list_item_t pointer if item
+ * has a parent, otherwise NULL.
+ */
+nested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item)
+{
+   if (!list_item)
+      return NULL;
+
+   return list_item->parent_item;
+}
+
+/**
+ * nested_list_item_get_parent_list:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches a pointer to the nested list of which the
+ * specified list item is a direct member.
+ *
+ * Returns: valid nested_list_t pointer if successful,
+ * otherwise NULL.
+ */
+nested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item)
+{
+   if (!list_item)
+      return NULL;
+
+   return list_item->parent_list;
+}
+
+/**
+ * nested_list_item_get_children:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches a pointer to the nested list of child items
+ * belonging to the specified list item.
+ *
+ * Returns: valid nested_list_t pointer if item has
+ * children, otherwise NULL.
+ */
+nested_list_t *nested_list_item_get_children(nested_list_item_t *list_item)
+{
+   if (!list_item ||
+       !list_item->children ||
+       (RBUF_LEN(list_item->children->items) < 1))
+      return NULL;
+
+   return list_item->children;
+}
+
+/**
+ * nested_list_item_get_id:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches the id string of the specified list item,
+ * as set by nested_list_add_item().
+ *
+ * Returns: item id if successful, otherwise NULL.
+ */
+const char *nested_list_item_get_id(nested_list_item_t *list_item)
+{
+   if (!list_item)
+      return NULL;
+
+   return list_item->id;
+}
+
+/**
+ * nested_list_item_get_address:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ * @delim     : delimiter to use when concatenating
+ *              individual item ids into a an @address
+ *              string
+ * @address   : a delimited list of item identifiers,
+ *              corresponding to item 'levels'
+ * @len       : length of supplied @address char array
+ * Fetches a compound @address string corresponding to
+ * the specified item's 'position' in the top level
+ * nested list of which it is a member. The resultant
+ * @address may be used to find the item when calling
+ * nested_list_get_item() on the top level nested list.
+ *
+ * Returns: true if successful, otherwise false.
+ */
+bool nested_list_item_get_address(nested_list_item_t *list_item,
+      const char *delim, char *address, size_t len)
+{
+   nested_list_item_t *current_item = list_item;
+   struct string_list id_list       = {0};
+   bool success                     = false;
+   union string_list_elem_attr attr;
+   size_t i;
+
+   if (!list_item ||
+       string_is_empty(delim) ||
+       !address ||
+       (len < 1))
+      goto end;
+
+   address[0] = '\0';
+   attr.i     = 0;
+
+   /* If this is an item of the top level
+    * list, just copy the item id directly */
+   if (!list_item->parent_item)
+   {
+      strlcpy(address, list_item->id, len);
+      success = true;
+      goto end;
+   }
+
+   /* ...otherwise we have to combine the ids
+    * of the item and all of its 'ancestors' */
+   string_list_initialize(&id_list);
+
+   /* Fetch all ids */
+   do
+   {
+      const char *id = current_item->id;
+
+      if (string_is_empty(id) ||
+          !string_list_append(&id_list, id, attr))
+         goto end;
+
+      current_item = current_item->parent_item;
+   }
+   while (current_item);
+
+   if (id_list.size < 1)
+      goto end;
+
+   /* Build address string */
+   for (i = id_list.size; i > 0; i--)
+   {
+      const char *id = id_list.elems[i - 1].data;
+
+      if (string_is_empty(id))
+         goto end;
+
+      strlcat(address, id, len);
+      if (i > 1)
+         strlcat(address, delim, len);
+   }
+
+   success = true;
+end:
+   string_list_deinitialize(&id_list);
+   return success;
+}
+
+/**
+ * nested_list_item_get_value:
+ *
+ * @list_item : pointer to nested_list_item_t object
+ *
+ * Fetches the value (user data) associated with the
+ * specified list item.
+ *
+ * Returns: pointer to user data if set, otherwise
+ * NULL.
+ */
+const void *nested_list_item_get_value(nested_list_item_t *list_item)
+{
+   if (!list_item)
+      return NULL;
+
+   return list_item->value;
+}
diff --git a/deps/libretro-common/lists/string_list.c b/deps/libretro-common/lists/string_list.c
new file mode 100644 (file)
index 0000000..d7fa1d1
--- /dev/null
@@ -0,0 +1,539 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (string_list.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <lists/string_list.h>
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+#include <string/stdstring.h>
+
+static bool string_list_deinitialize_internal(struct string_list *list)
+{
+   if (!list)
+      return false;
+
+   if (list->elems)
+   {
+      unsigned i;
+      for (i = 0; i < list->size; i++)
+      {
+         if (list->elems[i].data)
+            free(list->elems[i].data);
+         if (list->elems[i].userdata)
+            free(list->elems[i].userdata);
+         list->elems[i].data     = NULL;
+         list->elems[i].userdata = NULL;
+      }
+
+      free(list->elems);
+   }
+
+   list->elems = NULL;
+
+   return true;
+}
+
+/**
+ * string_list_capacity:
+ * @list             : pointer to string list
+ * @cap              : new capacity for string list.
+ *
+ * Change maximum capacity of string list's size.
+ *
+ * @return true if successful, otherwise false.
+ **/
+static bool string_list_capacity(struct string_list *list, size_t cap)
+{
+   struct string_list_elem *new_data = (struct string_list_elem*)
+      realloc(list->elems, cap * sizeof(*new_data));
+
+   if (!new_data)
+      return false;
+
+   if (cap > list->cap)
+      memset(&new_data[list->cap], 0, sizeof(*new_data) * (cap - list->cap));
+
+   list->elems = new_data;
+   list->cap   = cap;
+   return true;
+}
+
+/**
+ * string_list_free
+ * @list             : pointer to string list object
+ *
+ * Frees a string list.
+ **/
+void string_list_free(struct string_list *list)
+{
+   if (!list)
+      return;
+
+   string_list_deinitialize_internal(list);
+
+   free(list);
+}
+
+bool string_list_deinitialize(struct string_list *list)
+{
+   if (!list)
+      return false;
+   if (!string_list_deinitialize_internal(list))
+      return false;
+   list->elems              = NULL;
+   list->size               = 0;
+   list->cap                = 0;
+   return true;
+}
+
+/**
+ * string_list_new:
+ *
+ * Creates a new string list. Has to be freed manually.
+ *
+ * @return New string list if successful, otherwise NULL.
+ **/
+struct string_list *string_list_new(void)
+{
+   struct string_list_elem *
+      elems                 = NULL;
+   struct string_list *list = (struct string_list*)
+      malloc(sizeof(*list));
+   if (!list)
+      return NULL;
+
+   if (!(elems = (struct string_list_elem*)
+      calloc(32, sizeof(*elems))))
+   {
+      string_list_free(list);
+      return NULL;
+   }
+
+   list->elems              = elems;
+   list->size               = 0;
+   list->cap                = 32;
+
+   return list;
+}
+
+bool string_list_initialize(struct string_list *list)
+{
+   struct string_list_elem *
+      elems                 = NULL;
+   if (!list)
+      return false;
+   if (!(elems = (struct string_list_elem*)
+      calloc(32, sizeof(*elems))))
+   {
+      string_list_deinitialize(list);
+      return false;
+   }
+   list->elems              = elems;
+   list->size               = 0;
+   list->cap                = 32;
+   return true;
+}
+
+/**
+ * string_list_append:
+ * @list             : pointer to string list
+ * @elem             : element to add to the string list
+ * @attr             : attributes of new element.
+ *
+ * Appends a new element to the string list.
+ *
+ * @return true if successful, otherwise false.
+ **/
+bool string_list_append(struct string_list *list, const char *elem,
+      union string_list_elem_attr attr)
+{
+   char *data_dup = NULL;
+
+   /* Note: If 'list' is incorrectly initialised
+    * (i.e. if struct is zero initialised and
+    * string_list_initialize() is not called on
+    * it) capacity will be zero. This will cause
+    * a segfault. Handle this case by forcing the new
+    * capacity to a fixed size of 32 */
+   if (list->size >= list->cap &&
+         !string_list_capacity(list,
+               (list->cap > 0) ? (list->cap * 2) : 32))
+      return false;
+
+   if (!(data_dup = strdup(elem)))
+      return false;
+
+   list->elems[list->size].data = data_dup;
+   list->elems[list->size].attr = attr;
+
+   list->size++;
+   return true;
+}
+
+/**
+ * string_list_append_n:
+ * @list             : pointer to string list
+ * @elem             : element to add to the string list
+ * @length           : read at most this many bytes from elem
+ * @attr             : attributes of new element.
+ *
+ * Appends a new element to the string list.
+ *
+ * @return true if successful, otherwise false.
+ **/
+bool string_list_append_n(struct string_list *list, const char *elem,
+      unsigned length, union string_list_elem_attr attr)
+{
+   char *data_dup = NULL;
+
+   if (list->size >= list->cap &&
+         !string_list_capacity(list, list->cap * 2))
+      return false;
+
+   if (!(data_dup = (char*)malloc(length + 1)))
+      return false;
+
+   strlcpy(data_dup, elem, length + 1);
+
+   list->elems[list->size].data = data_dup;
+   list->elems[list->size].attr = attr;
+
+   list->size++;
+   return true;
+}
+
+/**
+ * string_list_set:
+ * @list             : pointer to string list
+ * @idx              : index of element in string list
+ * @str              : value for the element.
+ *
+ * Set value of element inside string list.
+ **/
+void string_list_set(struct string_list *list,
+      unsigned idx, const char *str)
+{
+   free(list->elems[idx].data);
+   list->elems[idx].data = strdup(str);
+}
+
+/**
+ * string_list_join_concat:
+ * @buffer           : buffer that @list will be joined to.
+ * @size             : length of @buffer.
+ * @list             : pointer to string list.
+ * @delim            : delimiter character for @list.
+ *
+ * A string list will be joined/concatenated as a
+ * string to @buffer, delimited by @delim.
+ **/
+void string_list_join_concat(char *buffer, size_t size,
+      const struct string_list *list, const char *delim)
+{
+   size_t i;
+   size_t len = strlen_size(buffer, size);
+
+   /* If buffer is already 'full', nothing
+    * further can be added
+    * > This condition will also be triggered
+    *   if buffer is not NULL-terminated,
+    *   in which case any attempt to increment
+    *   buffer or decrement size would lead to
+    *   undefined behaviour */
+   if (len >= size)
+      return;
+
+   buffer += len;
+   size   -= len;
+
+   for (i = 0; i < list->size; i++)
+   {
+      strlcat(buffer, list->elems[i].data, size);
+      if ((i + 1) < list->size)
+         strlcat(buffer, delim, size);
+   }
+}
+
+/**
+ * string_split:
+ * @str              : string to turn into a string list
+ * @delim            : delimiter character to use for splitting the string.
+ *
+ * Creates a new string list based on string @str, delimited by @delim.
+ *
+ * Returns: new string list if successful, otherwise NULL.
+ */
+struct string_list *string_split(const char *str, const char *delim)
+{
+   char *save      = NULL;
+   char *copy      = NULL;
+   const char *tmp = NULL;
+   struct string_list *list = string_list_new();
+
+   if (!list)
+      return NULL;
+
+   if (!(copy = strdup(str)))
+      goto error;
+
+   tmp = strtok_r(copy, delim, &save);
+   while (tmp)
+   {
+      union string_list_elem_attr attr;
+
+      attr.i = 0;
+
+      if (!string_list_append(list, tmp, attr))
+         goto error;
+
+      tmp = strtok_r(NULL, delim, &save);
+   }
+
+   free(copy);
+   return list;
+
+error:
+   string_list_free(list);
+   free(copy);
+   return NULL;
+}
+
+bool string_split_noalloc(struct string_list *list,
+      const char *str, const char *delim)
+{
+   char *save      = NULL;
+   char *copy      = NULL;
+   const char *tmp = NULL;
+
+   if (!list)
+      return false;
+
+   if (!(copy = strdup(str)))
+      return false;
+
+   tmp             = strtok_r(copy, delim, &save);
+   while (tmp)
+   {
+      union string_list_elem_attr attr;
+
+      attr.i = 0;
+
+      if (!string_list_append(list, tmp, attr))
+      {
+         free(copy);
+         return false;
+      }
+
+      tmp = strtok_r(NULL, delim, &save);
+   }
+
+   free(copy);
+   return true;
+}
+
+/**
+ * string_separate:
+ * @str              : string to turn into a string list
+ * @delim            : delimiter character to use for separating the string.
+ *
+ * Creates a new string list based on string @str, delimited by @delim.
+ * Includes empty strings - i.e. two adjacent delimiters will resolve
+ * to a string list element of "".
+ *
+ * @return New string list if successful, otherwise NULL.
+ **/
+struct string_list *string_separate(char *str, const char *delim)
+{
+   char *token              = NULL;
+   char **str_ptr           = NULL;
+   struct string_list *list = NULL;
+
+   /* Sanity check */
+   if (!str || string_is_empty(delim))
+      return NULL;
+   if (!(list = string_list_new()))
+          return NULL;
+
+   str_ptr = &str;
+   token   = string_tokenize(str_ptr, delim);
+
+   while (token)
+   {
+      union string_list_elem_attr attr;
+
+      attr.i = 0;
+
+      if (!string_list_append(list, token, attr))
+      {
+         free(token);
+         string_list_free(list);
+         return NULL;
+      }
+
+      free(token);
+      token = string_tokenize(str_ptr, delim);
+   }
+
+   return list;
+}
+
+bool string_separate_noalloc(
+      struct string_list *list,
+      char *str, const char *delim)
+{
+   char *token              = NULL;
+   char **str_ptr           = NULL;
+
+   /* Sanity check */
+   if (!str || string_is_empty(delim) || !list)
+      return false;
+
+   str_ptr = &str;
+   token   = string_tokenize(str_ptr, delim);
+
+   while (token)
+   {
+      union string_list_elem_attr attr;
+
+      attr.i = 0;
+
+      if (!string_list_append(list, token, attr))
+      {
+         free(token);
+         return false;
+      }
+
+      free(token);
+      token = string_tokenize(str_ptr, delim);
+   }
+
+   return true;
+}
+
+/**
+ * string_list_find_elem:
+ *
+ * @param list
+ * Pointer to string list
+ * @param elem
+ * Element to find inside the string list.
+ *
+ * Searches for an element (@elem) inside the string list.
+ *
+ * @return Number of elements found, otherwise 0.
+ */
+int string_list_find_elem(const struct string_list *list, const char *elem)
+{
+   if (list)
+   {
+      size_t i;
+      for (i = 0; i < list->size; i++)
+      {
+         if (string_is_equal_noncase(list->elems[i].data, elem))
+            return (int)(i + 1);
+      }
+   }
+   return 0;
+}
+
+/**
+ * string_list_find_elem_prefix:
+ *
+ * @param list
+ * Pointer to string list
+ * @param prefix
+ * Prefix to append to @elem
+ * @param elem
+ * Element to find inside the string list.
+ *
+ * Searches for an element (@elem) inside the string list. Will
+ * also search for the same element prefixed by @prefix.
+ *
+ * @return true if element could be found, otherwise false.
+ */
+bool string_list_find_elem_prefix(const struct string_list *list,
+      const char *prefix, const char *elem)
+{
+   size_t i;
+   char prefixed[255];
+   if (!list)
+      return false;
+   strlcpy(prefixed, prefix, sizeof(prefixed));
+   strlcat(prefixed, elem,   sizeof(prefixed));
+   for (i = 0; i < list->size; i++)
+   {
+      if (     string_is_equal_noncase(list->elems[i].data, elem)
+            || string_is_equal_noncase(list->elems[i].data, prefixed))
+         return true;
+   }
+   return false;
+}
+
+struct string_list *string_list_clone(const struct string_list *src)
+{
+   size_t i;
+   struct string_list_elem 
+      *elems              = NULL;
+   struct string_list 
+      *dest               = (struct string_list*)
+      malloc(sizeof(struct string_list));
+
+   if (!dest)
+      return NULL;
+
+   dest->elems            = NULL;
+   dest->size             = src->size;
+   if (src->cap < dest->size)
+      dest->cap           = dest->size;
+   else 
+      dest->cap           = src->cap;
+
+   if (!(elems = (struct string_list_elem*)
+      calloc(dest->cap, sizeof(struct string_list_elem))))
+   {
+      free(dest);
+      return NULL;
+   }
+
+   dest->elems            = elems;
+
+   for (i = 0; i < src->size; i++)
+   {
+      const char *_src       = src->elems[i].data;
+      size_t      len        = _src ? strlen(_src) : 0;
+
+      dest->elems[i].data    = NULL;
+      dest->elems[i].attr    = src->elems[i].attr;
+
+      if (len != 0)
+      {
+         char *result        = (char*)malloc(len + 1);
+         strcpy(result, _src);
+         dest->elems[i].data = result;
+      }
+   }
+
+   return dest;
+}
diff --git a/deps/libretro-common/lists/vector_list.c b/deps/libretro-common/lists/vector_list.c
new file mode 100644 (file)
index 0000000..063c571
--- /dev/null
@@ -0,0 +1,95 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (vector_list.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <boolean.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+/* default type is void*, override by defining VECTOR_LIST_TYPE before inclusion */
+#ifndef VECTOR_LIST_TYPE
+#define VECTOR_LIST_TYPE void*
+#define VECTOR_LIST_TYPE_DEFINED
+#endif
+
+/* default name is void, override by defining VECTOR_LIST_NAME before inclusion */
+#ifndef VECTOR_LIST_NAME
+#define VECTOR_LIST_NAME void
+#define VECTOR_LIST_NAME_DEFINED
+#endif
+
+#define CAT_I(a,b) a##b
+#define CAT(a,b) CAT_I(a, b)
+#define MAKE_TYPE_NAME() CAT(VECTOR_LIST_NAME, _vector_list)
+#define TYPE_NAME() MAKE_TYPE_NAME()
+
+struct TYPE_NAME()
+{
+   /* VECTOR_LIST_TYPE for pointers will expand to a pointer-to-pointer */
+   VECTOR_LIST_TYPE *data;
+   unsigned size;
+   unsigned count;
+};
+
+static struct TYPE_NAME()* CAT(TYPE_NAME(), _new(void))
+{
+   struct TYPE_NAME() *list = (struct TYPE_NAME()*)calloc(1, sizeof(*list));
+
+   list->size = 8;
+   list->data = (VECTOR_LIST_TYPE*)calloc(list->size, sizeof(*list->data));
+
+   return list;
+}
+
+static bool CAT(TYPE_NAME(), _append(struct TYPE_NAME() *list, VECTOR_LIST_TYPE elem))
+{
+   if (list->size == list->count)
+   {
+      list->size *= 2;
+      list->data = (VECTOR_LIST_TYPE*)realloc(list->data, list->size * sizeof(*list->data));
+
+      if (!list->data)
+         return false;
+   }
+
+   list->data[list->count] = elem;
+   list->count++;
+
+   return true;
+}
+
+static void CAT(TYPE_NAME(), _free(struct TYPE_NAME() *list))
+{
+   if (list)
+   {
+      if (list->data)
+         free(list->data);
+      free(list);
+   }
+}
+
+#ifdef VECTOR_LIST_TYPE_DEFINED
+#undef VECTOR_LIST_TYPE
+#endif
+
+#ifdef VECTOR_LIST_NAME_DEFINED
+#undef VECTOR_LIST_NAME
+#endif
diff --git a/deps/libretro-common/media/media_detect_cd.c b/deps/libretro-common/media/media_detect_cd.c
new file mode 100644 (file)
index 0000000..f19bae7
--- /dev/null
@@ -0,0 +1,570 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (media_detect_cd.c).
+* ---------------------------------------------------------------------------------------
+*
+* 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 <media/media_detect_cd.h>
+#include <streams/file_stream.h>
+#include <string/stdstring.h>
+#include <file/file_path.h>
+#include <retro_miscellaneous.h>
+
+/*#define MEDIA_CUE_PARSE_DEBUG*/
+
+static void media_zero_trailing_spaces(char *buf, size_t len)
+{
+   int i;
+
+   for (i = len - 1; i >= 0; i--)
+   {
+      if (buf[i] == ' ')
+         buf[i] = '\0';
+      else if (buf[i] != '\0')
+         break;
+   }
+}
+
+static bool media_skip_spaces(const char **buf, size_t len)
+{
+   bool found = false;
+   unsigned i;
+
+   if (!buf || !*buf || !**buf)
+      return false;
+
+   for (i = 0; i < len; i++)
+   {
+      if ((*buf)[i] == ' ' || (*buf)[i] == '\t')
+         continue;
+
+      *buf += i;
+      found = true;
+      break;
+   }
+
+   if (found)
+      return true;
+
+   return false;
+}
+
+/* Fill in "info" with detected CD info. Use this when you have a cue file and want it parsed to find the first data track and any pregap info. */
+bool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info)
+{
+   RFILE *file = NULL;
+   char *line = NULL;
+   char track_path[PATH_MAX_LENGTH] = {0};
+   char track_abs_path[PATH_MAX_LENGTH] = {0};
+   char track_mode[11] = {0};
+   bool found_file = false;
+   bool found_track = false;
+   unsigned first_data_track = 0;
+   uint64_t data_track_pregap_bytes = 0;
+
+   if (string_is_empty(path) || !info)
+      return false;
+
+   file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0);
+
+   if (!file)
+   {
+#ifdef MEDIA_CUE_PARSE_DEBUG
+      printf("[MEDIA] Could not open cue path for reading: %s\n", path);
+      fflush(stdout);
+#endif
+      return false;
+   }
+
+   while (!filestream_eof(file) && (line = filestream_getline(file)))
+   {
+      size_t len = 0;
+      const char *command = NULL;
+
+      if (string_is_empty(line))
+      {
+         free(line);
+         continue;
+      }
+
+      len     = strlen(line);
+      command = line;
+
+      media_skip_spaces(&command, len);
+
+      if (!found_file && !strncasecmp(command, "FILE", 4))
+      {
+         const char *file = command + 4;
+         media_skip_spaces(&file, len - 4);
+
+         if (!string_is_empty(file))
+         {
+            const char *file_end = NULL;
+            size_t file_len = 0;
+            bool quoted = false;
+
+            if (file[0] == '"')
+            {
+               quoted = true;
+               file++;
+            }
+
+            if (quoted)
+               file_end = strchr(file, '\"');
+            else
+               file_end = strchr(file, ' ');
+
+            if (file_end)
+            {
+               file_len = file_end - file;
+               memcpy(track_path, file, file_len);
+               found_file = true;
+#ifdef MEDIA_CUE_PARSE_DEBUG
+               printf("Found file: %s\n", track_path);
+               fflush(stdout);
+#endif
+            }
+         }
+      }
+      else if (found_file && !found_track && !strncasecmp(command, "TRACK", 5))
+      {
+         const char *track = command + 5;
+         media_skip_spaces(&track, len - 5);
+
+         if (!string_is_empty(track))
+         {
+            char *ptr             = NULL;
+            unsigned track_number = (unsigned)strtol(track, &ptr, 10);
+#ifdef MEDIA_CUE_PARSE_DEBUG
+            printf("Found track: %d\n", track_number);
+            fflush(stdout);
+#endif
+            track++;
+
+            if (track[0] && track[0] != ' ' && track[0] != '\t')
+               track++;
+
+            if (!string_is_empty(track))
+            {
+               media_skip_spaces(&track, strlen(track));
+#ifdef MEDIA_CUE_PARSE_DEBUG
+               printf("Found track type: %s\n", track);
+               fflush(stdout);
+#endif
+               if (!strncasecmp(track, "MODE", 4))
+               {
+                  first_data_track = track_number;
+                  found_track = true;
+                  strlcpy(track_mode, track, sizeof(track_mode));
+               }
+               else
+                  found_file = false;
+            }
+         }
+      }
+      else if (found_file && found_track && first_data_track && !strncasecmp(command, "INDEX", 5))
+      {
+         const char *index = command + 5;
+         media_skip_spaces(&index, len - 5);
+
+         if (!string_is_empty(index))
+         {
+            char *ptr             = NULL;
+            unsigned index_number = (unsigned)strtol(index, &ptr, 10);
+
+            if (index_number == 1)
+            {
+               const char *pregap = index + 1;
+
+               if (pregap[0] && pregap[0] != ' ' && pregap[0] != '\t')
+                  pregap++;
+
+               if (!string_is_empty(pregap))
+               {
+                  media_skip_spaces(&pregap, strlen(pregap));
+                  found_file = false;
+                  found_track = false;
+
+                  if (first_data_track && !string_is_empty(track_mode))
+                  {
+                     unsigned track_sector_size = 0;
+                     unsigned track_mode_number = 0;
+
+                     if (strlen(track_mode) == 10)
+                     {
+                        sscanf(track_mode, "MODE%d/%d", (int*)&track_mode_number, (int*)&track_sector_size);
+#ifdef MEDIA_CUE_PARSE_DEBUG
+                        printf("Found track mode %d with sector size %d\n", track_mode_number, track_sector_size);
+                        fflush(stdout);
+#endif
+                        if ((track_mode_number == 1 || track_mode_number == 2) && track_sector_size)
+                        {
+                           unsigned min = 0;
+                           unsigned sec = 0;
+                           unsigned frame = 0;
+                           sscanf(pregap, "%02d:%02d:%02d", (int*)&min, (int*)&sec, (int*)&frame);
+
+                           if (min || sec || frame || strstr(pregap, "00:00:00"))
+                           {
+                              data_track_pregap_bytes = ((min * 60 + sec) * 75 + frame) * track_sector_size;
+#ifdef MEDIA_CUE_PARSE_DEBUG
+                              printf("Found pregap of %02d:%02d:%02d (bytes: %" PRIu64 ")\n", min, sec, frame, data_track_pregap_bytes);
+                              fflush(stdout);
+#endif
+                              break;
+                           }
+                        }
+                     }
+                  }
+               }
+            }
+         }
+      }
+
+      free(line);
+   }
+
+   filestream_close(file);
+
+   if (!string_is_empty(track_path))
+   {
+      if (strstr(track_path, "/") || strstr(track_path, "\\"))
+      {
+#ifdef MEDIA_CUE_PARSE_DEBUG
+         printf("using path %s\n", track_path);
+         fflush(stdout);
+#endif
+         return media_detect_cd_info(track_path, data_track_pregap_bytes, info);
+      }
+
+      fill_pathname_basedir(track_abs_path, path, sizeof(track_abs_path));
+      strlcat(track_abs_path, track_path, sizeof(track_abs_path));
+#ifdef MEDIA_CUE_PARSE_DEBUG
+      printf("using abs path %s\n", track_abs_path);
+      fflush(stdout);
+#endif
+      return media_detect_cd_info(track_abs_path, data_track_pregap_bytes, info);
+   }
+
+   return true;
+}
+
+/* Fill in "info" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */
+bool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info)
+{
+   RFILE *file;
+
+   if (string_is_empty(path) || !info)
+      return false;
+
+   file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0);
+
+   if (!file)
+   {
+#ifdef MEDIA_CUE_PARSE_DEBUG
+      printf("[MEDIA] Could not open path for reading: %s\n", path);
+      fflush(stdout);
+#endif
+      return false;
+   }
+
+   {
+      unsigned offset = 0;
+      unsigned sector_size = 0;
+      unsigned buf_size = 17 * 2352;
+      char *buf = (char*)calloc(1, buf_size);
+      int64_t read_bytes = 0;
+
+      if (!buf)
+         return false;
+
+      if (pregap_bytes)
+         filestream_seek(file, pregap_bytes, RETRO_VFS_SEEK_POSITION_START);
+
+      read_bytes = filestream_read(file, buf, buf_size);
+
+      if (read_bytes != buf_size)
+      {
+#ifdef MEDIA_CUE_PARSE_DEBUG
+         printf("[MEDIA] Could not read from media: got %" PRId64 " bytes instead of %d.\n", read_bytes, buf_size);
+         fflush(stdout);
+#endif
+         filestream_close(file);
+         free(buf);
+         return false;
+      }
+
+      /* 12-byte sync field at the start of every sector, common to both mode1 and mode2 data tracks
+       * (when at least sync data is requested). This is a CD-ROM standard feature and not specific to any game devices,
+       * and as such should not be part of any system-specific detection or "magic" bytes.
+       * Depending on what parts of a sector were requested from the disc, the user data might start at
+       * byte offset 0, 4, 8, 12, 16 or 24. Cue sheets only specify the total number of bytes requested from the sectors
+       * of a track (like 2048 or 2352) and it is then assumed based on the size/mode as to what fields are present. */
+      if (!memcmp(buf, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12))
+      {
+         /* Assume track data contains all fields. */
+         sector_size = 2352;
+
+         if (buf[15] == 2)
+         {
+            /* assume Mode 2 formed (formless is rarely used) */
+            offset = 24;
+         }
+         else
+         {
+            /* assume Mode 1 */
+            offset = 16;
+         }
+      }
+      else
+      {
+         /* Assume sectors only contain user data instead. */
+         offset = 0;
+         sector_size = 2048;
+      }
+
+      if (!memcmp(buf + offset, "SEGADISCSYSTEM",
+               STRLEN_CONST("SEGADISCSYSTEM")))
+      {
+         const char *title_pos  = NULL;
+         const char *serial_pos = NULL;
+
+         /* All discs currently in Redump for MCD start with SEGADISCSYSTEM. There are other strings mentioned elsewhere online,
+          * but I have not seen any real examples of them. */
+         info->system_id = MEDIA_CD_SYSTEM_MEGA_CD;
+
+         strcpy_literal(info->system, "Sega CD / Mega CD");
+
+         title_pos = buf + offset + 0x150;
+
+         if (media_skip_spaces(&title_pos, 48))
+         {
+            memcpy(info->title, title_pos, 48 - (title_pos - (buf + offset + 0x150)));
+            media_zero_trailing_spaces(info->title, sizeof(info->title));
+         }
+         else
+         {
+            info->title[0] = 'N';
+            info->title[1] = '/';
+            info->title[2] = 'A';
+            info->title[3] = '\0';
+         }
+
+         serial_pos = buf + offset + 0x183;
+
+         if (media_skip_spaces(&serial_pos, 8))
+         {
+            memcpy(info->serial, serial_pos, 8 - (serial_pos - (buf + offset + 0x183)));
+            media_zero_trailing_spaces(info->serial, sizeof(info->serial));
+         }
+         else
+         {
+            info->serial[0] = 'N';
+            info->serial[1] = '/';
+            info->serial[2] = 'A';
+            info->serial[3] = '\0';
+         }
+      }
+      else if (!memcmp(buf + offset, "SEGA SEGASATURN",
+               STRLEN_CONST("SEGA SEGASATURN")))
+      {
+         const char *title_pos        = NULL;
+         const char *serial_pos       = NULL;
+         const char *version_pos      = NULL;
+         const char *release_date_pos = NULL;
+
+         info->system_id = MEDIA_CD_SYSTEM_SATURN;
+
+         strcpy_literal(info->system, "Sega Saturn");
+
+         title_pos = buf + offset + 0x60;
+
+         if (media_skip_spaces(&title_pos, 112))
+         {
+            memcpy(info->title, title_pos, 112 - (title_pos - (buf + offset + 0x60)));
+            media_zero_trailing_spaces(info->title, sizeof(info->title));
+         }
+         else
+         {
+            info->title [0] = 'N';
+            info->title [1] = '/';
+            info->title [2] = 'A';
+            info->title [3] = '\0';
+         }
+
+         serial_pos = buf + offset + 0x20;
+
+         if (media_skip_spaces(&serial_pos, 10))
+         {
+            memcpy(info->serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x20)));
+            media_zero_trailing_spaces(info->serial, sizeof(info->serial));
+         }
+         else
+         {
+            info->serial[0] = 'N';
+            info->serial[1] = '/';
+            info->serial[2] = 'A';
+            info->serial[3] = '\0';
+         }
+
+         version_pos = buf + offset + 0x2a;
+
+         if (media_skip_spaces(&version_pos, 6))
+         {
+            memcpy(info->version, version_pos, 6 - (version_pos - (buf + offset + 0x2a)));
+            media_zero_trailing_spaces(info->version, sizeof(info->version));
+         }
+         else
+         {
+            info->version[0] = 'N';
+            info->version[1] = '/';
+            info->version[2] = 'A';
+            info->version[3] = '\0';
+         }
+
+         release_date_pos = buf + offset + 0x30;
+
+         if (media_skip_spaces(&release_date_pos, 8))
+         {
+            memcpy(info->release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x30)));
+            media_zero_trailing_spaces(info->release_date, sizeof(info->release_date));
+         }
+         else
+         {
+            info->release_date[0] = 'N';
+            info->release_date[1] = '/';
+            info->release_date[2] = 'A';
+            info->release_date[3] = '\0';
+         }
+      }
+      else if (!memcmp(buf + offset, "SEGA SEGAKATANA", STRLEN_CONST("SEGA SEGAKATANA")))
+      {
+         const char *title_pos        = NULL;
+         const char *serial_pos       = NULL;
+         const char *version_pos      = NULL;
+         const char *release_date_pos = NULL;
+
+         info->system_id = MEDIA_CD_SYSTEM_DREAMCAST;
+
+         strcpy_literal(info->system, "Sega Dreamcast");
+
+         title_pos = buf + offset + 0x80;
+
+         if (media_skip_spaces(&title_pos, 96))
+         {
+            memcpy(info->title, title_pos, 96 - (title_pos - (buf + offset + 0x80)));
+            media_zero_trailing_spaces(info->title, sizeof(info->title));
+         }
+         else
+         {
+            info->title       [0] = 'N';
+            info->title       [1] = '/';
+            info->title       [2] = 'A';
+            info->title       [3] = '\0';
+         }
+
+         serial_pos = buf + offset + 0x40;
+
+         if (media_skip_spaces(&serial_pos, 10))
+         {
+            memcpy(info->serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x40)));
+            media_zero_trailing_spaces(info->serial, sizeof(info->serial));
+         }
+         else
+         {
+            info->serial      [0] = 'N';
+            info->serial      [1] = '/';
+            info->serial      [2] = 'A';
+            info->serial      [3] = '\0';
+         }
+
+         version_pos = buf + offset + 0x4a;
+
+         if (media_skip_spaces(&version_pos, 6))
+         {
+            memcpy(info->version, version_pos, 6 - (version_pos - (buf + offset + 0x4a)));
+            media_zero_trailing_spaces(info->version, sizeof(info->version));
+         }
+         else
+         {
+            info->version     [0] = 'N';
+            info->version     [1] = '/';
+            info->version     [2] = 'A';
+            info->version     [3] = '\0';
+         }
+
+         release_date_pos = buf + offset + 0x50;
+
+         if (media_skip_spaces(&release_date_pos, 8))
+         {
+            memcpy(info->release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x50)));
+            media_zero_trailing_spaces(info->release_date, sizeof(info->release_date));
+         }
+         else
+         {
+            info->release_date[0] = 'N';
+            info->release_date[1] = '/';
+            info->release_date[2] = 'A';
+            info->release_date[3] = '\0';
+         }
+      }
+      /* Primary Volume Descriptor fields of ISO9660 */
+      else if (!memcmp(buf + offset + (16 * sector_size), "\1CD001\1\0PLAYSTATION", 19))
+      {
+         const char *title_pos = NULL;
+
+         info->system_id = MEDIA_CD_SYSTEM_PSX;
+
+         strcpy_literal(info->system, "Sony PlayStation");
+
+         title_pos = buf + offset + (16 * sector_size) + 40;
+
+         if (media_skip_spaces(&title_pos, 32))
+         {
+            memcpy(info->title, title_pos, 32 - (title_pos - (buf + offset + (16 * sector_size) + 40)));
+            media_zero_trailing_spaces(info->title, sizeof(info->title));
+         }
+         else
+         {
+            info->title       [0] = 'N';
+            info->title       [1] = '/';
+            info->title       [2] = 'A';
+            info->title       [3] = '\0';
+         }
+      }
+      else if (!memcmp(buf + offset, "\x01\x5a\x5a\x5a\x5a\x5a\x01\x00\x00\x00\x00\x00", 12))
+      {
+         info->system_id = MEDIA_CD_SYSTEM_3DO;
+
+         strcpy_literal(info->system, "3DO");
+      }
+      else if (!memcmp(buf + offset + 0x950, "PC Engine CD-ROM SYSTEM", 23))
+      {
+         info->system_id = MEDIA_CD_SYSTEM_PC_ENGINE_CD;
+
+         strcpy_literal(info->system, "TurboGrafx-CD / PC-Engine CD");
+      }
+
+      free(buf);
+   }
+
+   filestream_close(file);
+
+   return true;
+}
diff --git a/deps/libretro-common/memmap/memalign.c b/deps/libretro-common/memmap/memalign.c
new file mode 100644 (file)
index 0000000..14eaeff
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (memalign.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+
+#include <memalign.h>
+
+void *memalign_alloc(size_t boundary, size_t size)
+{
+   void **place   = NULL;
+   uintptr_t addr = 0;
+   void *ptr      = (void*)malloc(boundary + size + sizeof(uintptr_t));
+   if (!ptr)
+      return NULL;
+
+   addr           = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary)
+      & ~(boundary - 1);
+   place          = (void**)addr;
+   place[-1]      = ptr;
+
+   return (void*)addr;
+}
+
+void memalign_free(void *ptr)
+{
+   void **p = NULL;
+   if (!ptr)
+      return;
+
+   p = (void**)ptr;
+   free(p[-1]);
+}
+
+void *memalign_alloc_aligned(size_t size)
+{
+#if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_M_X64) || defined(_WIN64)
+   return memalign_alloc(64, size);
+#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(GEKKO) || defined(_M_IX86)
+   return memalign_alloc(32, size);
+#else
+   return memalign_alloc(32, size);
+#endif
+}
diff --git a/deps/libretro-common/memmap/memmap.c b/deps/libretro-common/memmap/memmap.c
new file mode 100644 (file)
index 0000000..5062aba
--- /dev/null
@@ -0,0 +1,164 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (memmap.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <memmap.h>
+
+#ifndef PROT_READ
+#define PROT_READ         0x1  /* Page can be read */
+#endif
+
+#ifndef PROT_WRITE
+#define PROT_WRITE        0x2  /* Page can be written. */
+#endif
+
+#ifndef PROT_READWRITE
+#define PROT_READWRITE    0x3  /* Page can be written to and read from. */
+#endif
+
+#ifndef PROT_EXEC
+#define PROT_EXEC         0x4  /* Page can be executed. */
+#endif
+
+#ifndef PROT_NONE
+#define PROT_NONE         0x0  /* Page can not be accessed. */
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED        ((void *) -1)
+#endif
+
+#ifdef _WIN32
+void* mmap(void *addr, size_t len, int prot, int flags,
+      int fildes, size_t offset)
+{
+   void     *map = (void*)NULL;
+   HANDLE handle = INVALID_HANDLE_VALUE;
+
+   switch (prot)
+   {
+      case PROT_READ:
+      default:
+         handle = CreateFileMapping((HANDLE)
+               _get_osfhandle(fildes), 0, PAGE_READONLY, 0,
+               len, 0);
+         if (!handle)
+            break;
+         map = (void*)MapViewOfFile(handle, FILE_MAP_READ, 0, 0, len);
+         CloseHandle(handle);
+         break;
+      case PROT_WRITE:
+         handle = CreateFileMapping((HANDLE)
+               _get_osfhandle(fildes),0,PAGE_READWRITE,0,
+               len, 0);
+         if (!handle)
+            break;
+         map = (void*)MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, len);
+         CloseHandle(handle);
+         break;
+      case PROT_READWRITE:
+         handle = CreateFileMapping((HANDLE)
+               _get_osfhandle(fildes),0,PAGE_READWRITE,0,
+               len, 0);
+         if (!handle)
+            break;
+         map = (void*)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, len);
+         CloseHandle(handle);
+         break;
+   }
+
+   if (map == (void*)NULL)
+      return((void*)MAP_FAILED);
+   return((void*) ((int8_t*)map + offset));
+}
+
+int munmap(void *addr, size_t length)
+{
+   if (!UnmapViewOfFile(addr))
+      return -1;
+   return 0;
+}
+
+int mprotect(void *addr, size_t len, int prot)
+{
+   /* Incomplete, just assumes PAGE_EXECUTE_READWRITE right now
+    * instead of correctly handling prot */
+   prot = 0;
+   if (prot & (PROT_READ | PROT_WRITE | PROT_EXEC))
+      prot = PAGE_EXECUTE_READWRITE;
+   return VirtualProtect(addr, len, prot, 0);
+}
+
+#elif !defined(HAVE_MMAN)
+void* mmap(void *addr, size_t len, int prot, int flags,
+      int fildes, size_t offset)
+{
+   return malloc(len);
+}
+
+int munmap(void *addr, size_t len)
+{
+   free(addr);
+   return 0;
+}
+
+int mprotect(void *addr, size_t len, int prot)
+{
+   /* stub - not really needed at this point
+    * since this codepath has no dynarecs. */
+   return 0;
+}
+
+#endif
+
+#if defined(__MACH__) && defined(__arm__)
+#include <libkern/OSCacheControl.h>
+#endif
+
+int memsync(void *start, void *end)
+{
+   size_t len = (char*)end - (char*)start;
+#if defined(__MACH__) && defined(__arm__)
+   sys_dcache_flush(start ,len);
+   sys_icache_invalidate(start, len);
+   return 0;
+#elif defined(__arm__) && !defined(__QNX__)
+   (void)len;
+   __clear_cache(start, end);
+   return 0;
+#elif defined(HAVE_MMAN)
+   return msync(start, len, MS_SYNC | MS_INVALIDATE
+#ifdef __QNX__
+         MS_CACHE_ONLY
+#endif
+         );
+#else
+   (void)len;
+   return 0;
+#endif
+}
+
+int memprotect(void *addr, size_t len)
+{
+   return mprotect(addr, len, PROT_READ | PROT_WRITE | PROT_EXEC);
+}
diff --git a/deps/libretro-common/net/net_compat.c b/deps/libretro-common/net/net_compat.c
new file mode 100644 (file)
index 0000000..e291bbe
--- /dev/null
@@ -0,0 +1,639 @@
+/* Copyright  (C) 2010-2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_compat.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+
+#include <compat/strl.h>
+#include <retro_miscellaneous.h>
+#include <retro_timers.h>
+
+#include <net/net_compat.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{
+   struct sockaddr_storage addr;
+
+   switch (af)
+   {
+      case AF_INET:
+         memcpy(&((struct sockaddr_in*)&addr)->sin_addr, src,
+            sizeof(struct in_addr));
+         break;
+#ifdef HAVE_INET6
+      case AF_INET6:
+         memcpy(&((struct sockaddr_in6*)&addr)->sin6_addr, src,
+            sizeof(struct in6_addr));
+         break;
+#endif
+      default:
+         return NULL;
+   }
+
+   addr.ss_family = af;
+   if (getnameinfo((struct sockaddr*)&addr, sizeof(addr), dst, size, NULL, 0,
+         NI_NUMERICHOST))
+      return NULL;
+
+   return dst;
+}
+
+int inet_pton(int af, const char *src, void *dst)
+{
+   struct addrinfo *addr = NULL;
+   struct addrinfo hints = {0};
+
+   switch (af)
+   {
+      case AF_INET:
+#ifdef HAVE_INET6
+      case AF_INET6:
+#endif
+         break;
+      default:
+         return -1;
+   }
+
+   hints.ai_family = af;
+   hints.ai_flags  = AI_NUMERICHOST;
+   switch (getaddrinfo(src, NULL, &hints, &addr))
+   {
+      case 0:
+         break;
+      case EAI_NONAME:
+         return 0;
+      default:
+         return -1;
+   }
+
+   if (!addr)
+      return -1;
+
+   switch (af)
+   {
+      case AF_INET:
+         memcpy(dst, &((struct sockaddr_in*)addr->ai_addr)->sin_addr,
+            sizeof(struct in_addr));
+         break;
+#ifdef HAVE_INET6
+      case AF_INET6:
+         memcpy(dst, &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr,
+            sizeof(struct in6_addr));
+         break;
+#endif
+      default:
+         break;
+   }
+
+   freeaddrinfo(addr);
+
+   return 1;
+}
+#endif
+
+#elif defined(_XBOX)
+struct hostent *gethostbyname(const char *name)
+{
+   static struct in_addr addr = {0};
+   static struct hostent he   = {0};
+   WSAEVENT event;
+   XNDNS          *dns = NULL;
+   struct hostent *ret = NULL;
+
+   if (!name)
+      return NULL;
+
+   event = WSACreateEvent();
+
+   XNetDnsLookup(name, event, &dns);
+   if (!dns)
+      goto done;
+
+   WaitForSingleObject((HANDLE)event, INFINITE);
+
+   if (dns->iStatus)
+      goto done;
+
+   memcpy(&addr, dns->aina, sizeof(addr));
+
+   he.h_name      = NULL;
+   he.h_aliases   = NULL;
+   he.h_addrtype  = AF_INET;
+   he.h_length    = sizeof(addr);
+   he.h_addr_list = &he.h_addr;
+   he.h_addr      = (char*)&addr;
+
+   ret = &he;
+
+done:
+   WSACloseEvent(event);
+   if (dns)
+      XNetDnsRelease(dns);
+
+   return ret;
+}
+
+#elif defined(VITA)
+#define COMPAT_NET_INIT_SIZE 0x80000
+
+char *inet_ntoa(struct in_addr in)
+{
+   static char ip_addr[16];
+
+   sceNetInetNtop(AF_INET, &in, ip_addr, sizeof(ip_addr));
+
+   return ip_addr;
+}
+
+int inet_aton(const char *cp, struct in_addr *inp)
+{
+   return sceNetInetPton(AF_INET, cp, inp);
+}
+
+uint32_t inet_addr(const char *cp)
+{
+   struct in_addr in;
+
+   return (sceNetInetPton(AF_INET, cp, &in) == 1) ? in.s_addr : INADDR_NONE;
+}
+
+struct hostent *gethostbyname(const char *name)
+{
+   static struct SceNetInAddr addr = {0};
+   static struct hostent      he   = {0};
+   int rid;
+   struct hostent *ret = NULL;
+
+   if (!name)
+      return NULL;
+
+   rid = sceNetResolverCreate("resolver", NULL, 0);
+   if (rid < 0)
+      return NULL;
+
+   if (sceNetResolverStartNtoa(rid, name, &addr, 0, 0, 0) < 0)
+      goto done;
+
+   he.h_name      = NULL;
+   he.h_aliases   = NULL;
+   he.h_addrtype  = AF_INET;
+   he.h_length    = sizeof(addr);
+   he.h_addr_list = &he.h_addr;
+   he.h_addr      = (char*)&addr;
+
+   ret = &he;
+
+done:
+   sceNetResolverDestroy(rid);
+
+   return ret;
+}
+
+#elif defined(GEKKO)
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{
+   const char *addr_str = inet_ntoa(*(struct in_addr*)src);
+
+   if (addr_str)
+   {
+      strlcpy(dst, addr_str, size);
+
+      return dst;
+   }
+
+   return NULL;
+}
+
+int inet_pton(int af, const char *src, void *dst)
+{
+   if (inet_aton(src, (struct in_addr*)dst))
+      return 1;
+
+   return 0;
+}
+
+#elif defined(WIIU)
+#include <malloc.h>
+
+static int _net_compat_thread_entry(int argc, const char **argv)
+{
+   void *buf = memalign(128, WIIU_RCVBUF + WIIU_SNDBUF);
+
+   if (!buf)
+      return -1;
+
+   somemopt(1, buf, WIIU_RCVBUF + WIIU_SNDBUF, 0);
+
+   free(buf);
+
+   return 0;
+}
+
+static void _net_compat_thread_cleanup(OSThread *thread, void *stack)
+{
+   free(stack);
+}
+
+#elif defined(_3DS)
+#include <malloc.h>
+#include <3ds/types.h>
+#include <3ds/services/soc.h>
+
+#define SOC_ALIGN      0x1000
+#define SOC_BUFFERSIZE 0x100000
+#endif
+
+int getaddrinfo_retro(const char *node, const char *service,
+      struct addrinfo *hints, struct addrinfo **res)
+{
+#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
+   struct addrinfo default_hints = {0};
+
+   if (!hints)
+      hints            = &default_hints;
+   if (!hints->ai_family)
+      hints->ai_family = AF_INET;
+
+   if (!node)
+      node = (hints->ai_flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
+#endif
+
+#ifdef HAVE_SOCKET_LEGACY
+   {
+      struct addrinfo    *info = (struct addrinfo*)calloc(1, sizeof(*info));
+      struct sockaddr_in *addr = (struct sockaddr_in*)malloc(sizeof(*addr));
+
+      if (!info || !addr)
+         goto failure;
+
+      info->ai_family   = AF_INET;
+      info->ai_socktype = hints->ai_socktype;
+      info->ai_protocol = hints->ai_protocol;
+      info->ai_addrlen  = sizeof(*addr);
+      info->ai_addr     = (struct sockaddr*)addr;
+      /* We ignore AI_CANONNAME; ai_canonname is always NULL. */
+
+      addr->sin_family = AF_INET;
+
+      if (service)
+      {
+         /* We can only handle numeric ports; ignore AI_NUMERICSERV. */
+         char *service_end = NULL;
+         uint16_t port     = (uint16_t)strtoul(service, &service_end, 10);
+
+         if (service_end == service || *service_end)
+            goto failure;
+
+         addr->sin_port = htons(port);
+      }
+
+      if (hints->ai_flags & AI_NUMERICHOST)
+      {
+         if (!inet_aton(node, &addr->sin_addr))
+            goto failure;
+      }
+      else
+      {
+         struct hostent *host = gethostbyname(node);
+
+         if (!host || !host->h_addr)
+            goto failure;
+
+         memcpy(&addr->sin_addr, host->h_addr, sizeof(addr->sin_addr));
+      }
+
+      *res = info;
+
+      return 0;
+
+failure:
+      free(addr);
+      free(info);
+
+      return -1;
+   }
+#else
+   return getaddrinfo(node, service, hints, res);
+#endif
+}
+
+void freeaddrinfo_retro(struct addrinfo *res)
+{
+#ifdef HAVE_SOCKET_LEGACY
+   if (res)
+   {
+      free(res->ai_addr);
+      free(res);
+   }
+#else
+   freeaddrinfo(res);
+#endif
+}
+
+int getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,
+      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
+{
+#ifdef HAVE_SOCKET_LEGACY
+   const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;
+
+   /* We cannot perform reverse DNS lookups here; ignore the following flags:
+      NI_NAMEREQD
+      NI_NOFQDN
+      NI_NUMERICHOST (always enforced)
+    */
+   if (host && hostlen)
+   {
+      const char *_host = inet_ntoa(addr4->sin_addr);
+
+      if (!_host)
+         return -1;
+
+      strlcpy(host, _host, hostlen);
+   }
+
+   /* We cannot get service names here; ignore the following flags:
+      NI_DGRAM
+      NI_NUMERICSERV (always enforced)
+    */
+   if (serv && servlen)
+      snprintf(serv, servlen, "%hu", (unsigned short)ntohs(addr4->sin_port));
+
+   return 0;
+#else
+   return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+#endif
+}
+
+bool addr_6to4(struct sockaddr_storage *addr)
+{
+#ifdef HAVE_INET6
+   /* ::ffff:a.b.c.d */
+   static const uint16_t preffix[] = {0,0,0,0,0,0xffff};
+   uint32_t address;
+   uint16_t port;
+   struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)addr;
+   struct sockaddr_in  *addr4 = (struct sockaddr_in*)addr;
+
+   switch (addr->ss_family)
+   {
+      case AF_INET:
+         /* No need to convert. */
+         return true;
+      case AF_INET6:
+         /* Is the address provided an IPv4? */
+         if (!memcmp(&addr6->sin6_addr, preffix, sizeof(preffix)))
+            break;
+      default:
+         /* We don't know how to handle this. */
+         return false;
+   }
+
+   memcpy(&address, ((uint8_t*)&addr6->sin6_addr) + sizeof(preffix),
+      sizeof(address));
+   port = addr6->sin6_port;
+
+   memset(addr, 0, sizeof(*addr));
+
+   addr4->sin_family = AF_INET;
+   addr4->sin_port   = port;
+   memcpy(&addr4->sin_addr, &address, sizeof(addr4->sin_addr));
+#endif
+
+   return true;
+}
+
+bool ipv4_is_lan_address(const struct sockaddr_in *addr)
+{
+   static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000};
+   static const uint32_t masks[]   = {0xFF000000, 0xFFF00000, 0xFFFF0000};
+   size_t i;
+   uint32_t uaddr;
+
+   memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
+   uaddr = ntohl(uaddr);
+
+   for (i = 0; i < ARRAY_SIZE(subnets); i++)
+      if ((uaddr & masks[i]) == subnets[i])
+         return true;
+
+   return false;
+}
+
+bool ipv4_is_cgnat_address(const struct sockaddr_in *addr)
+{
+   static const uint32_t subnet = 0x64400000;
+   static const uint32_t mask   = 0xFFC00000;
+   uint32_t uaddr;
+
+   memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));
+   uaddr = ntohl(uaddr);
+
+   return (uaddr & mask) == subnet;
+}
+
+/**
+ * network_init:
+ *
+ * Platform specific socket library initialization.
+ *
+ * @return true if successful, otherwise false.
+ **/
+bool network_init(void)
+{
+#if defined(_WIN32)
+   static bool initialized = false;
+
+   if (!initialized)
+   {
+      WSADATA wsaData;
+
+      if (WSAStartup(MAKEWORD(2, 2), &wsaData))
+      {
+         WSACleanup();
+
+         return false;
+      }
+
+      initialized = true;
+   }
+
+   return true;
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   static bool initialized = false;
+
+   if (!initialized)
+   {
+      int tries;
+
+      sysModuleLoad(SYSMODULE_NET);
+
+      netInitialize();
+      if (netCtlInit() < 0)
+         goto failure;
+
+      for (tries = 10;;)
+      {
+         int state;
+
+         if (netCtlGetState(&state) < 0)
+            goto failure;
+         if (state == NET_CTL_STATE_IPObtained)
+            break;
+
+         if (!(--tries))
+            goto failure;
+
+         retro_sleep(500);
+      }
+
+      initialized = true;
+   }
+
+   return true;
+
+failure:
+   netCtlTerm();
+   netFinalizeNetwork();
+
+   sysModuleUnload(SYSMODULE_NET);
+
+   return false;
+#elif defined(VITA)
+   if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)
+   {
+      SceNetInitParam param;
+      void *net_compat_memory = malloc(COMPAT_NET_INIT_SIZE);
+
+      if (!net_compat_memory)
+         return false;
+
+      param.memory = net_compat_memory;
+      param.size   = COMPAT_NET_INIT_SIZE;
+      param.flags  = 0;
+
+      if (sceNetInit(&param) < 0)
+         goto failure;
+      if (sceNetCtlInit() < 0)
+         goto failure;
+
+      return true;
+
+failure:
+      sceNetCtlTerm();
+      sceNetTerm();
+
+      free(net_compat_memory);
+
+      return false;
+   }
+
+   return true;
+#elif defined(GEKKO)
+   static bool initialized = false;
+
+   if (!initialized)
+   {
+      char localip[16] = {0};
+      char netmask[16] = {0};
+      char gateway[16] = {0};
+
+      if (if_config(localip, netmask, gateway, true, 10) < 0)
+      {
+         net_deinit();
+
+         return false;
+      }
+
+      initialized = true;
+   }
+
+   return true;
+#elif defined(WIIU)
+   static OSThread net_compat_thread;
+   static bool initialized = false;
+
+   if (!initialized)
+   {
+      void *stack = malloc(0x1000);
+
+      if (!stack)
+         return false;
+
+      socket_lib_init();
+
+      if (!OSCreateThread(&net_compat_thread, _net_compat_thread_entry,
+            0, NULL, (void*)((size_t)stack + 0x1000), 0x1000, 3,
+            OS_THREAD_ATTRIB_AFFINITY_ANY))
+      {
+         free(stack);
+
+         return false;
+      }
+
+      OSSetThreadName(&net_compat_thread, "Network compat thread");
+      OSSetThreadDeallocator(&net_compat_thread, _net_compat_thread_cleanup);
+      OSResumeThread(&net_compat_thread);
+
+      initialized = true;
+   }
+
+   return true;
+#elif defined(_3DS)
+   static bool initialized = false;
+
+   if (!initialized)
+   {
+      u32 *net_compat_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
+
+      if (!net_compat_memory)
+         return false;
+
+      /* WIFI init */
+      if (socInit(net_compat_memory, SOC_BUFFERSIZE))
+      {
+         socExit();
+
+         free(net_compat_memory);
+
+         return false;
+      }
+
+      initialized = true;
+   }
+
+   return true;
+#else
+   static bool initialized = false;
+
+   if (!initialized)
+   {
+      /* Do not like SIGPIPE killing our app. */
+      signal(SIGPIPE, SIG_IGN);
+
+      initialized = true;
+   }
+
+   return true;
+#endif
+}
diff --git a/deps/libretro-common/net/net_http.c b/deps/libretro-common/net/net_http.c
new file mode 100644 (file)
index 0000000..8d39773
--- /dev/null
@@ -0,0 +1,1236 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_http.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <net/net_http.h>
+#include <net/net_compat.h>
+#include <net/net_socket.h>
+#ifdef HAVE_SSL
+#include <net/net_socket_ssl.h>
+#endif
+#include <compat/strl.h>
+#include <string/stdstring.h>
+#include <string.h>
+#include <retro_common_api.h>
+#include <retro_miscellaneous.h>
+
+enum
+{
+   P_HEADER_TOP = 0,
+   P_HEADER,
+   P_BODY,
+   P_BODY_CHUNKLEN,
+   P_DONE,
+   P_ERROR
+};
+
+enum
+{
+   T_FULL = 0,
+   T_LEN,
+   T_CHUNK
+};
+
+struct http_socket_state_t
+{
+   void *ssl_ctx;
+   int fd;
+   bool ssl;
+};
+
+struct http_t
+{
+   char *data;
+   struct http_socket_state_t sock_state; /* ptr alignment */
+   size_t pos;
+   size_t len;
+   size_t buflen;
+   int status;
+   char part;
+   char bodytype;
+   bool error;
+};
+
+struct http_connection_t
+{
+   char *domain;
+   char *location;
+   char *urlcopy;
+   char *scan;
+   char *methodcopy;
+   char *contenttypecopy;
+   char *postdatacopy;
+   char *useragentcopy;
+   char *headerscopy;
+   struct http_socket_state_t sock_state; /* ptr alignment */
+   int port;
+};
+
+/**
+ * net_http_urlencode:
+ *
+ * URL Encode a string
+ * caller is responsible for deleting the destination buffer
+ **/
+void net_http_urlencode(char **dest, const char *source)
+{
+   static const char urlencode_lut[256] = 
+   {
+      0,       /* 0   */
+      0,       /* 1   */
+      0,       /* 2   */
+      0,       /* 3   */
+      0,       /* 4   */
+      0,       /* 5   */
+      0,       /* 6   */
+      0,       /* 7   */
+      0,       /* 8   */
+      0,       /* 9   */
+      0,       /* 10  */
+      0,       /* 11  */
+      0,       /* 12  */
+      0,       /* 13  */
+      0,       /* 14  */
+      0,       /* 15  */
+      0,       /* 16  */
+      0,       /* 17  */
+      0,       /* 18  */
+      0,       /* 19  */
+      0,       /* 20  */
+      0,       /* 21  */
+      0,       /* 22  */
+      0,       /* 23  */
+      0,       /* 24  */
+      0,       /* 25  */
+      0,       /* 26  */
+      0,       /* 27  */
+      0,       /* 28  */
+      0,       /* 29  */
+      0,       /* 30  */
+      0,       /* 31  */
+      0,       /* 32  */
+      0,       /* 33  */
+      0,       /* 34  */
+      0,       /* 35  */
+      0,       /* 36  */
+      0,       /* 37  */
+      0,       /* 38  */
+      0,       /* 39  */
+      0,       /* 40  */
+      0,       /* 41  */
+      '*',     /* 42  */
+      0,       /* 43  */
+      0,       /* 44  */
+      '-',     /* 45  */
+      '.',     /* 46  */
+      '/',     /* 47  */
+      '0',     /* 48  */
+      '1',     /* 49  */
+      '2',     /* 50  */
+      '3',     /* 51  */
+      '4',     /* 52  */
+      '5',     /* 53  */
+      '6',     /* 54  */
+      '7',     /* 55  */
+      '8',     /* 56  */
+      '9',     /* 57  */
+      0,       /* 58  */
+      0,       /* 59  */
+      0,       /* 60  */
+      0,       /* 61  */
+      0,       /* 62  */
+      0,       /* 63  */
+      0,       /* 64  */
+      'A',     /* 65  */
+      'B',     /* 66  */
+      'C',     /* 67  */
+      'D',     /* 68  */
+      'E',     /* 69  */
+      'F',     /* 70  */
+      'G',     /* 71  */
+      'H',     /* 72  */
+      'I',     /* 73  */
+      'J',     /* 74  */
+      'K',     /* 75  */
+      'L',     /* 76  */
+      'M',     /* 77  */
+      'N',     /* 78  */
+      'O',     /* 79  */
+      'P',     /* 80  */
+      'Q',     /* 81  */
+      'R',     /* 82  */
+      'S',     /* 83  */
+      'T',     /* 84  */
+      'U',     /* 85  */
+      'V',     /* 86  */
+      'W',     /* 87  */
+      'X',     /* 88  */
+      'Y',     /* 89  */
+      'Z',     /* 90  */
+      0,       /* 91  */
+      0,       /* 92  */
+      0,       /* 93  */
+      0,       /* 94  */
+      '_',     /* 95  */
+      0,       /* 96  */
+      'a',     /* 97  */
+      'b',     /* 98  */
+      'c',     /* 99  */
+      'd',     /* 100 */
+      'e',     /* 101 */
+      'f',     /* 102 */
+      'g',     /* 103 */
+      'h',     /* 104 */
+      'i',     /* 105 */
+      'j',     /* 106 */
+      'k',     /* 107 */
+      'l',     /* 108 */
+      'm',     /* 109 */
+      'n',     /* 110 */
+      'o',     /* 111 */
+      'p',     /* 112 */
+      'q',     /* 113 */
+      'r',     /* 114 */
+      's',     /* 115 */
+      't',     /* 116 */
+      'u',     /* 117 */
+      'v',     /* 118 */
+      'w',     /* 119 */
+      'x',     /* 120 */
+      'y',     /* 121 */
+      'z',     /* 122 */
+      0,       /* 123 */
+      0,       /* 124 */
+      0,       /* 125 */
+      0,       /* 126 */
+      0,       /* 127 */
+      0,       /* 128 */
+      0,       /* 129 */
+      0,       /* 130 */
+      0,       /* 131 */
+      0,       /* 132 */
+      0,       /* 133 */
+      0,       /* 134 */
+      0,       /* 135 */
+      0,       /* 136 */
+      0,       /* 137 */
+      0,       /* 138 */
+      0,       /* 139 */
+      0,       /* 140 */
+      0,       /* 141 */
+      0,       /* 142 */
+      0,       /* 143 */
+      0,       /* 144 */
+      0,       /* 145 */
+      0,       /* 146 */
+      0,       /* 147 */
+      0,       /* 148 */
+      0,       /* 149 */
+      0,       /* 150 */
+      0,       /* 151 */
+      0,       /* 152 */
+      0,       /* 153 */
+      0,       /* 154 */
+      0,       /* 155 */
+      0,       /* 156 */
+      0,       /* 157 */
+      0,       /* 158 */
+      0,       /* 159 */
+      0,       /* 160 */
+      0,       /* 161 */
+      0,       /* 162 */
+      0,       /* 163 */
+      0,       /* 164 */
+      0,       /* 165 */
+      0,       /* 166 */
+      0,       /* 167 */
+      0,       /* 168 */
+      0,       /* 169 */
+      0,       /* 170 */
+      0,       /* 171 */
+      0,       /* 172 */
+      0,       /* 173 */
+      0,       /* 174 */
+      0,       /* 175 */
+      0,       /* 176 */
+      0,       /* 177 */
+      0,       /* 178 */
+      0,       /* 179 */
+      0,       /* 180 */
+      0,       /* 181 */
+      0,       /* 182 */
+      0,       /* 183 */
+      0,       /* 184 */
+      0,       /* 185 */
+      0,       /* 186 */
+      0,       /* 187 */
+      0,       /* 188 */
+      0,       /* 189 */
+      0,       /* 190 */
+      0,       /* 191 */
+      0,       /* 192 */
+      0,       /* 193 */
+      0,       /* 194 */
+      0,       /* 195 */
+      0,       /* 196 */
+      0,       /* 197 */
+      0,       /* 198 */
+      0,       /* 199 */
+      0,       /* 200 */
+      0,       /* 201 */
+      0,       /* 202 */
+      0,       /* 203 */
+      0,       /* 204 */
+      0,       /* 205 */
+      0,       /* 206 */
+      0,       /* 207 */
+      0,       /* 208 */
+      0,       /* 209 */
+      0,       /* 210 */
+      0,       /* 211 */
+      0,       /* 212 */
+      0,       /* 213 */
+      0,       /* 214 */
+      0,       /* 215 */
+      0,       /* 216 */
+      0,       /* 217 */
+      0,       /* 218 */
+      0,       /* 219 */
+      0,       /* 220 */
+      0,       /* 221 */
+      0,       /* 222 */
+      0,       /* 223 */
+      0,       /* 224 */
+      0,       /* 225 */
+      0,       /* 226 */
+      0,       /* 227 */
+      0,       /* 228 */
+      0,       /* 229 */
+      0,       /* 230 */
+      0,       /* 231 */
+      0,       /* 232 */
+      0,       /* 233 */
+      0,       /* 234 */
+      0,       /* 235 */
+      0,       /* 236 */
+      0,       /* 237 */
+      0,       /* 238 */
+      0,       /* 239 */
+      0,       /* 240 */
+      0,       /* 241 */
+      0,       /* 242 */
+      0,       /* 243 */
+      0,       /* 244 */
+      0,       /* 245 */
+      0,       /* 246 */
+      0,       /* 247 */
+      0,       /* 248 */
+      0,       /* 249 */
+      0,       /* 250 */
+      0,       /* 251 */
+      0,       /* 252 */
+      0,       /* 253 */
+      0,       /* 254 */
+      0        /* 255 */
+   };
+
+   /* Assume every character will be encoded, so we need 3 times the space. */
+   size_t len                       = strlen(source) * 3 + 1;
+   size_t count                     = len;
+   char *enc                        = (char*)calloc(1, len);
+   *dest                            = enc;
+
+   for (; *source; source++)
+   {
+      int written = 0;
+
+      /* any non-ASCII character will just be encoded without question */
+      if ((unsigned)*source < sizeof(urlencode_lut) && urlencode_lut[(unsigned)*source])
+         written = snprintf(enc, count, "%c", urlencode_lut[(unsigned)*source]);
+      else
+         written = snprintf(enc, count, "%%%02X", *source & 0xFF);
+
+      if (written > 0)
+         count -= written;
+
+      while (*++enc);
+   }
+
+   (*dest)[len - 1] = '\0';
+}
+
+/**
+ * net_http_urlencode_full:
+ *
+ * Re-encode a full URL
+ **/
+void net_http_urlencode_full(char *dest,
+      const char *source, size_t size)
+{
+   size_t tmp_len;
+   size_t url_domain_len;
+   char url_domain[256];
+   char url_path[PATH_MAX_LENGTH];
+   size_t buf_pos                    = 0;
+   char *tmp                         = NULL;
+   int count                         = 0;
+
+   strlcpy(url_path, source, sizeof(url_path));
+   tmp = url_path;
+
+   while (count < 3 && tmp[0] != '\0')
+   {
+      tmp = strchr(tmp, '/');
+      count++;
+      tmp++;
+   }
+
+   tmp_len        = strlen(tmp);
+   url_domain_len = ((strlcpy(url_domain, source, tmp - url_path)) - tmp_len) - 1;
+   strlcpy(url_path,
+         source + url_domain_len + 1,
+         tmp_len + 1
+         );
+
+   tmp             = NULL;
+   net_http_urlencode(&tmp, url_path);
+   buf_pos         = strlcpy(dest, url_domain, size);
+   dest[buf_pos]   = '/';
+   dest[buf_pos+1] = '\0';
+   strlcat(dest, tmp, size);
+   free (tmp);
+}
+
+static int net_http_new_socket(struct http_connection_t *conn)
+{
+   struct addrinfo *addr = NULL, *next_addr = NULL;
+   int fd                = socket_init(
+         (void**)&addr, conn->port, conn->domain, SOCKET_TYPE_STREAM, 0);
+#ifdef HAVE_SSL
+   if (conn->sock_state.ssl)
+   {
+      if (fd < 0)
+         goto done;
+
+      if (!(conn->sock_state.ssl_ctx = ssl_socket_init(fd, conn->domain)))
+      {
+         socket_close(fd);
+         fd = -1;
+         goto done;
+      }
+
+      /* TODO: Properly figure out what's going wrong when the newer 
+         timeout/poll code interacts with mbed and winsock
+         https://github.com/libretro/RetroArch/issues/14742 */
+
+      /* Temp fix, don't use new timeout/poll code for cheevos http requests */
+         bool timeout = true;
+#ifdef __WIN32
+      if (!strcmp(conn->domain, "retroachievements.org"))
+         timeout = false;
+#endif
+
+      if (ssl_socket_connect(conn->sock_state.ssl_ctx, addr, timeout, true)
+            < 0)
+      {
+         fd = -1;
+         goto done;
+      }
+   }
+   else
+#endif
+   for (next_addr = addr; fd >= 0; fd = socket_next((void**)&next_addr))
+   {
+      if (socket_connect_with_timeout(fd, next_addr, 5000))
+         break;
+
+      socket_close(fd);
+   }
+
+#ifdef HAVE_SSL
+done:
+#endif
+   if (addr)
+      freeaddrinfo_retro(addr);
+
+   conn->sock_state.fd = fd;
+
+   return fd;
+}
+
+static void net_http_send_str(
+      struct http_socket_state_t *sock_state, bool *error,
+      const char *text, size_t text_size)
+{
+   if (*error)
+      return;
+#ifdef HAVE_SSL
+   if (sock_state->ssl)
+   {
+      if (!ssl_socket_send_all_blocking(
+               sock_state->ssl_ctx, text, text_size, true))
+         *error = true;
+   }
+   else
+#endif
+   {
+      if (!socket_send_all_blocking(
+               sock_state->fd, text, text_size, true))
+         *error = true;
+   }
+}
+
+struct http_connection_t *net_http_connection_new(const char *url,
+      const char *method, const char *data)
+{
+   struct http_connection_t *conn = NULL;
+
+   if (!url)
+      return NULL;
+   if (!(conn = (struct http_connection_t*)malloc(
+         sizeof(*conn))))
+      return NULL;
+
+   conn->domain            = NULL;
+   conn->location          = NULL;
+   conn->urlcopy           = NULL;
+   conn->scan              = NULL;
+   conn->methodcopy        = NULL;
+   conn->contenttypecopy   = NULL;
+   conn->postdatacopy      = NULL;
+   conn->useragentcopy     = NULL;
+   conn->headerscopy       = NULL;
+   conn->port              = 0;
+   conn->sock_state.fd     = 0;
+   conn->sock_state.ssl    = false;
+   conn->sock_state.ssl_ctx= NULL;
+
+   if (method)
+      conn->methodcopy     = strdup(method);
+
+   if (data)
+      conn->postdatacopy   = strdup(data);
+
+   if (!(conn->urlcopy = strdup(url)))
+      goto error;
+
+   if (!strncmp(url, "http://", STRLEN_CONST("http://")))
+      conn->scan           = conn->urlcopy + STRLEN_CONST("http://");
+   else if (!strncmp(url, "https://", STRLEN_CONST("https://")))
+   {
+      conn->scan           = conn->urlcopy + STRLEN_CONST("https://");
+      conn->sock_state.ssl = true;
+   }
+   else
+      goto error;
+
+   if (string_is_empty(conn->scan))
+      goto error;
+
+   conn->domain = conn->scan;
+
+   return conn;
+
+error:
+   if (conn->urlcopy)
+      free(conn->urlcopy);
+   if (conn->methodcopy)
+      free(conn->methodcopy);
+   if (conn->postdatacopy)
+      free(conn->postdatacopy);
+   conn->urlcopy      = NULL;
+   conn->methodcopy   = NULL;
+   conn->postdatacopy = NULL;
+   free(conn);
+   return NULL;
+}
+
+/**
+ * net_http_connection_iterate:
+ *
+ * Leaf function.
+ **/
+bool net_http_connection_iterate(struct http_connection_t *conn)
+{
+   if (!conn)
+      return false;
+
+   while (*conn->scan != '/' && *conn->scan != ':' && *conn->scan != '\0')
+      conn->scan++;
+
+   return true;
+}
+
+bool net_http_connection_done(struct http_connection_t *conn)
+{
+   int has_port = 0;
+
+   if (!conn || !conn->domain || !*conn->domain)
+      return false;
+
+   if (*conn->scan == ':')
+   {
+      /* domain followed by port, split off the port */
+      *conn->scan++ = '\0';
+
+      if (!isdigit((int)(*conn->scan)))
+         return false;
+
+      conn->port = (int)strtoul(conn->scan, &conn->scan, 10);
+      has_port   = 1;
+   }
+   else if (conn->port == 0)
+   {
+      /* port not specified, default to standard HTTP or HTTPS port */
+      if (conn->sock_state.ssl)
+         conn->port = 443;
+      else
+         conn->port = 80;
+   }
+
+   if (*conn->scan == '/')
+   {
+      /* domain followed by location - split off the location */
+      /*   site.com/path.html   or   site.com:80/path.html   */
+      *conn->scan    = '\0';
+      conn->location = conn->scan + 1;
+      return true;
+   }
+   else if (!*conn->scan)
+   {
+      /* domain with no location - point location at empty string */
+      /*   site.com   or   site.com:80   */
+      conn->location = conn->scan;
+      return true;
+   }
+   else if (*conn->scan == '?')
+   {
+      /* domain with no location, but still has query parms - point location at the query parms */
+      /*   site.com?param=3   or  site.com:80?param=3   */
+      if (!has_port)
+      {
+         /* if there wasn't a port, we have to expand the urlcopy so we can separate the two parts */
+         size_t domain_len   = strlen(conn->domain);
+         size_t location_len = strlen(conn->scan);
+         char* urlcopy       = (char*)malloc(domain_len + location_len + 2);
+         memcpy(urlcopy, conn->domain, domain_len);
+         urlcopy[domain_len] = '\0';
+         memcpy(urlcopy + domain_len + 1, conn->scan, location_len + 1);
+
+         free(conn->urlcopy);
+         conn->domain        = conn->urlcopy = urlcopy;
+         conn->location      = conn->scan    = urlcopy + domain_len + 1;
+      }
+      else /* There was a port, so overwriting the : will terminate the domain and we can just point at the ? */
+         conn->location      = conn->scan;
+
+      return true;
+   }
+
+   /* invalid character after domain/port */
+   return false;
+}
+
+void net_http_connection_free(struct http_connection_t *conn)
+{
+   if (!conn)
+      return;
+
+   if (conn->urlcopy)
+      free(conn->urlcopy);
+
+   if (conn->methodcopy)
+      free(conn->methodcopy);
+
+   if (conn->contenttypecopy)
+      free(conn->contenttypecopy);
+
+   if (conn->postdatacopy)
+      free(conn->postdatacopy);
+
+   if (conn->useragentcopy)
+      free(conn->useragentcopy);
+
+   if (conn->headerscopy)
+      free(conn->headerscopy);
+
+   conn->urlcopy         = NULL;
+   conn->methodcopy      = NULL;
+   conn->contenttypecopy = NULL;
+   conn->postdatacopy    = NULL;
+   conn->useragentcopy   = NULL;
+   conn->headerscopy     = NULL;
+
+   free(conn);
+}
+
+void net_http_connection_set_user_agent(
+      struct http_connection_t *conn, const char *user_agent)
+{
+   if (conn->useragentcopy)
+      free(conn->useragentcopy);
+
+   conn->useragentcopy = user_agent ? strdup(user_agent) : NULL;
+}
+
+void net_http_connection_set_headers(
+      struct http_connection_t *conn, const char *headers)
+{
+   if (conn->headerscopy)
+      free(conn->headerscopy);
+
+   conn->headerscopy = headers ? strdup(headers) : NULL;
+}
+
+const char *net_http_connection_url(struct http_connection_t *conn)
+{
+   return conn->urlcopy;
+}
+
+const char* net_http_connection_method(struct http_connection_t* conn)
+{
+   return conn->methodcopy;
+}
+
+struct http_t *net_http_new(struct http_connection_t *conn)
+{
+   bool error            = false;
+   int fd                = -1;
+   struct http_t *state  = NULL;
+
+   if (!conn)
+      goto error;
+
+   if ((fd = net_http_new_socket(conn)) < 0)
+      goto error;
+
+   error = false;
+
+   /* This is a bit lazy, but it works. */
+   if (conn->methodcopy)
+   {
+      net_http_send_str(&conn->sock_state, &error, conn->methodcopy,
+            strlen(conn->methodcopy));
+      net_http_send_str(&conn->sock_state, &error, " /",
+            STRLEN_CONST(" /"));
+   }
+   else
+   {
+      net_http_send_str(&conn->sock_state, &error, "GET /",
+            STRLEN_CONST("GET /"));
+   }
+
+   net_http_send_str(&conn->sock_state, &error, conn->location,
+         strlen(conn->location));
+   net_http_send_str(&conn->sock_state, &error, " HTTP/1.1\r\n",
+         STRLEN_CONST(" HTTP/1.1\r\n"));
+
+   net_http_send_str(&conn->sock_state, &error, "Host: ",
+         STRLEN_CONST("Host: "));
+   net_http_send_str(&conn->sock_state, &error, conn->domain,
+         strlen(conn->domain));
+
+   if (conn->port)
+   {
+      char portstr[16];
+
+      portstr[0] = '\0';
+
+      snprintf(portstr, sizeof(portstr), ":%i", conn->port);
+      net_http_send_str(&conn->sock_state, &error, portstr,
+            strlen(portstr));
+   }
+
+   net_http_send_str(&conn->sock_state, &error, "\r\n",
+         STRLEN_CONST("\r\n"));
+
+   /* Pre-formatted headers */
+   if (conn->headerscopy)
+      net_http_send_str(&conn->sock_state, &error, conn->headerscopy,
+            strlen(conn->headerscopy));
+   /* This is not being set anywhere yet */
+   else if (conn->contenttypecopy)
+   {
+      net_http_send_str(&conn->sock_state, &error, "Content-Type: ",
+            STRLEN_CONST("Content-Type: "));
+      net_http_send_str(&conn->sock_state, &error,
+            conn->contenttypecopy, strlen(conn->contenttypecopy));
+      net_http_send_str(&conn->sock_state, &error, "\r\n",
+            STRLEN_CONST("\r\n"));
+   }
+
+   if (conn->methodcopy && (string_is_equal(conn->methodcopy, "POST")))
+   {
+      size_t post_len, len;
+      char *len_str        = NULL;
+
+      if (!conn->postdatacopy)
+         goto error;
+
+      if (!conn->headerscopy)
+      {
+         if (!conn->contenttypecopy)
+            net_http_send_str(&conn->sock_state, &error,
+                  "Content-Type: application/x-www-form-urlencoded\r\n",
+                  STRLEN_CONST(
+                     "Content-Type: application/x-www-form-urlencoded\r\n"
+                     ));
+      }
+
+      net_http_send_str(&conn->sock_state, &error, "Content-Length: ",
+            STRLEN_CONST("Content-Length: "));
+
+      post_len = strlen(conn->postdatacopy);
+#ifdef _WIN32
+      len     = snprintf(NULL, 0, "%" PRIuPTR, post_len);
+      len_str = (char*)malloc(len + 1);
+      snprintf(len_str, len + 1, "%" PRIuPTR, post_len);
+#else
+      len     = snprintf(NULL, 0, "%llu", (long long unsigned)post_len);
+      len_str = (char*)malloc(len + 1);
+      snprintf(len_str, len + 1, "%llu", (long long unsigned)post_len);
+#endif
+
+      len_str[len] = '\0';
+
+      net_http_send_str(&conn->sock_state, &error, len_str,
+            strlen(len_str));
+      net_http_send_str(&conn->sock_state, &error, "\r\n",
+            STRLEN_CONST("\r\n"));
+
+      free(len_str);
+   }
+
+   net_http_send_str(&conn->sock_state, &error, "User-Agent: ",
+         STRLEN_CONST("User-Agent: "));
+   if (conn->useragentcopy)
+      net_http_send_str(&conn->sock_state, &error,
+            conn->useragentcopy, strlen(conn->useragentcopy));
+   else
+      net_http_send_str(&conn->sock_state, &error, "libretro",
+            STRLEN_CONST("libretro"));
+   net_http_send_str(&conn->sock_state, &error, "\r\n",
+         STRLEN_CONST("\r\n"));
+
+   net_http_send_str(&conn->sock_state, &error,
+         "Connection: close\r\n", STRLEN_CONST("Connection: close\r\n"));
+   net_http_send_str(&conn->sock_state, &error, "\r\n",
+         STRLEN_CONST("\r\n"));
+
+   if (conn->methodcopy && (string_is_equal(conn->methodcopy, "POST")))
+      net_http_send_str(&conn->sock_state, &error, conn->postdatacopy,
+            strlen(conn->postdatacopy));
+
+   if (error)
+      goto error;
+
+   state             = (struct http_t*)malloc(sizeof(struct http_t));
+   state->sock_state = conn->sock_state;
+   state->status     = -1;
+   state->data       = NULL;
+   state->part       = P_HEADER_TOP;
+   state->bodytype   = T_FULL;
+   state->error      = false;
+   state->pos        = 0;
+   state->len        = 0;
+   state->buflen     = 512;
+
+   if (!(state->data = (char*)malloc(state->buflen)))
+      goto error;
+
+   return state;
+
+error:
+   if (conn)
+   {
+      if (conn->methodcopy)
+         free(conn->methodcopy);
+      if (conn->contenttypecopy)
+         free(conn->contenttypecopy);
+      conn->methodcopy      = NULL;
+      conn->contenttypecopy = NULL;
+      conn->postdatacopy    = NULL;
+   }
+#ifdef HAVE_SSL
+   if (conn && conn->sock_state.ssl_ctx)
+   {
+      ssl_socket_close(conn->sock_state.ssl_ctx);
+      ssl_socket_free(conn->sock_state.ssl_ctx);
+      conn->sock_state.ssl_ctx = NULL;
+   }
+#else
+   if (fd >= 0)
+      socket_close(fd);
+#endif
+   if (state)
+      free(state);
+   return NULL;
+}
+
+/**
+ * net_http_fd:
+ *
+ * Leaf function.
+ *
+ * You can use this to call net_http_update
+ * only when something will happen; select() it for reading.
+ **/
+int net_http_fd(struct http_t *state)
+{
+   if (!state)
+      return -1;
+   return state->sock_state.fd;
+}
+
+/**
+ * net_http_update:
+ *
+ * @return true if it's done, or if something broke.
+ * @total will be 0 if it's not known.
+ **/
+bool net_http_update(struct http_t *state, size_t* progress, size_t* total)
+{
+   ssize_t newlen = 0;
+
+   if (!state)
+      return true;
+   if (state->error)
+   {
+      state->part   = P_ERROR;
+      state->status = -1;
+      return true;
+   }
+
+   if (state->part < P_BODY)
+   {
+      if (state->error)
+      {
+         state->part   = P_ERROR;
+         state->status = -1;
+         return true;
+      }
+
+#ifdef HAVE_SSL
+      if (state->sock_state.ssl && state->sock_state.ssl_ctx)
+         newlen = ssl_socket_receive_all_nonblocking(state->sock_state.ssl_ctx, &state->error,
+               (uint8_t*)state->data + state->pos,
+               state->buflen - state->pos);
+      else
+#endif
+         newlen = socket_receive_all_nonblocking(state->sock_state.fd, &state->error,
+               (uint8_t*)state->data + state->pos,
+               state->buflen - state->pos);
+
+      if (newlen < 0)
+      {
+         state->error  = true;
+         state->part   = P_ERROR;
+         state->status = -1;
+         return true;
+      }
+
+      if (state->pos + newlen >= state->buflen - 64)
+      {
+         state->buflen *= 2;
+         state->data    = (char*)realloc(state->data, state->buflen);
+      }
+      state->pos += newlen;
+
+      while (state->part < P_BODY)
+      {
+         char *dataend = state->data + state->pos;
+         char *lineend = (char*)memchr(state->data, '\n', state->pos);
+
+         if (!lineend)
+            break;
+
+         *lineend='\0';
+
+         if (lineend != state->data && lineend[-1]=='\r')
+            lineend[-1]='\0';
+
+         if (state->part == P_HEADER_TOP)
+         {
+            if (strncmp(state->data, "HTTP/1.", STRLEN_CONST("HTTP/1."))!=0)
+            {
+               state->error  = true;
+               state->part   = P_ERROR;
+               state->status = -1;
+               return true;
+            }
+            state->status    = (int)strtoul(state->data 
+                  + STRLEN_CONST("HTTP/1.1 "), NULL, 10);
+            state->part      = P_HEADER;
+         }
+         else
+         {
+            if (string_starts_with_case_insensitive(state->data, "Content-Length:"))
+            {
+               char* ptr = state->data + STRLEN_CONST("Content-Length:");
+               while (ISSPACE(*ptr))
+                  ++ptr;
+
+               state->bodytype = T_LEN;
+               state->len = strtol(ptr, NULL, 10);
+            }
+            if (string_is_equal_case_insensitive(state->data, "Transfer-Encoding: chunked"))
+               state->bodytype = T_CHUNK;
+
+            /* TODO: save headers somewhere */
+            if (state->data[0]=='\0')
+            {
+               state->part = P_BODY;
+               if (state->bodytype == T_CHUNK)
+                  state->part = P_BODY_CHUNKLEN;
+            }
+         }
+
+         memmove(state->data, lineend + 1, dataend-(lineend+1));
+         state->pos = (dataend-(lineend + 1));
+      }
+
+      if (state->part >= P_BODY)
+      {
+         newlen     = state->pos;
+         state->pos = 0;
+      }
+   }
+
+   if (state->part >= P_BODY && state->part < P_DONE)
+   {
+      if (!newlen)
+      {
+         if (state->error)
+            newlen = -1;
+         else
+         {
+#ifdef HAVE_SSL
+            if (state->sock_state.ssl && state->sock_state.ssl_ctx)
+               newlen = ssl_socket_receive_all_nonblocking(
+                  state->sock_state.ssl_ctx,
+                  &state->error,
+                  (uint8_t*)state->data + state->pos,
+                  state->buflen - state->pos);
+            else
+#endif
+               newlen = socket_receive_all_nonblocking(
+                  state->sock_state.fd,
+                  &state->error,
+                  (uint8_t*)state->data + state->pos,
+                  state->buflen - state->pos);
+         }
+
+         if (newlen < 0)
+         {
+            if (state->bodytype != T_FULL)
+            {
+               state->error  = true;
+               state->part   = P_ERROR;
+               state->status = -1;
+               return true;
+            }
+            state->part      = P_DONE;
+            state->data      = (char*)realloc(state->data, state->len);
+            newlen           = 0;
+         }
+
+         if (state->pos + newlen >= state->buflen - 64)
+         {
+            state->buflen   *= 2;
+            state->data      = (char*)realloc(state->data, state->buflen);
+         }
+      }
+
+parse_again:
+      if (state->bodytype == T_CHUNK)
+      {
+         if (state->part == P_BODY_CHUNKLEN)
+         {
+            state->pos      += newlen;
+
+            if (state->pos - state->len >= 2)
+            {
+               /*
+                * len=start of chunk including \r\n
+                * pos=end of data
+                */
+
+               char *fullend = state->data + state->pos;
+               char *end     = (char*)memchr(state->data + state->len + 2, '\n',
+                     state->pos - state->len - 2);
+
+               if (end)
+               {
+                  size_t chunklen = strtoul(state->data+state->len, NULL, 16);
+                  state->pos      = state->len;
+                  end++;
+
+                  memmove(state->data+state->len, end, fullend-end);
+
+                  state->len      = chunklen;
+                  newlen          = (fullend - end);
+
+                  /*
+                     len=num bytes
+                     newlen=unparsed bytes after \n
+                     pos=start of chunk including \r\n
+                     */
+
+                  state->part = P_BODY;
+                  if (state->len == 0)
+                  {
+                     state->part = P_DONE;
+                     state->len  = state->pos;
+                     state->data = (char*)realloc(state->data, state->len);
+                  }
+                  goto parse_again;
+               }
+            }
+         }
+         else if (state->part == P_BODY)
+         {
+            if ((size_t)newlen >= state->len)
+            {
+               state->pos += state->len;
+               newlen     -= state->len;
+               state->len  = state->pos;
+               state->part = P_BODY_CHUNKLEN;
+               goto parse_again;
+            }
+            state->pos += newlen;
+            state->len -= newlen;
+         }
+      }
+      else
+      {
+         state->pos += newlen;
+
+         if (state->pos > state->len)
+         {
+            state->error  = true;
+            state->part   = P_ERROR;
+            state->status = -1;
+            return true;
+         }
+         else if (state->pos == state->len)
+         {
+            state->part   = P_DONE;
+            state->data   = (char*)realloc(state->data, state->len);
+         }
+      }
+   }
+
+   if (progress)
+      *progress = state->pos;
+
+   if (total)
+   {
+      if (state->bodytype == T_LEN)
+         *total = state->len;
+      else
+         *total = 0;
+   }
+
+   return (state->part == P_DONE);
+}
+
+/**
+ * net_http_status:
+ *
+ * Report HTTP status. 200, 404, or whatever.
+ *
+ * Leaf function.
+ * 
+ * @return HTTP status code.
+ **/
+int net_http_status(struct http_t *state)
+{
+   if (!state)
+      return -1;
+   return state->status;
+}
+
+/**
+ * net_http_data:
+ *
+ * Leaf function.
+ *
+ * @return the downloaded data. The returned buffer is owned by the
+ * HTTP handler; it's freed by net_http_delete().
+ * If the status is not 20x and accept_error is false, it returns NULL.
+ **/
+uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_error)
+{
+   if (!state)
+      return NULL;
+
+   if (!accept_error && (state->error || state->status < 200 || state->status > 299))
+   {
+      if (len)
+         *len = 0;
+      return NULL;
+   }
+
+   if (len)
+      *len    = state->len;
+
+   return (uint8_t*)state->data;
+}
+
+/**
+ * net_http_delete:
+ *
+ * Cleans up all memory.
+ **/
+void net_http_delete(struct http_t *state)
+{
+   if (!state)
+      return;
+
+   if (state->sock_state.fd >= 0)
+   {
+#ifdef HAVE_SSL
+      if (state->sock_state.ssl && state->sock_state.ssl_ctx)
+      {
+         ssl_socket_close(state->sock_state.ssl_ctx);
+         ssl_socket_free(state->sock_state.ssl_ctx);
+         state->sock_state.ssl_ctx = NULL;
+      }
+      else
+#endif
+      socket_close(state->sock_state.fd);
+   }
+   free(state);
+}
+
+/**
+ * net_http_error:
+ *
+ * Leaf function
+ **/
+bool net_http_error(struct http_t *state)
+{
+   return (state->error || state->status < 200 || state->status > 299);
+}
diff --git a/deps/libretro-common/net/net_http_parse.c b/deps/libretro-common/net/net_http_parse.c
new file mode 100644 (file)
index 0000000..7f2914c
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_http_parse.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <compat/strcasestr.h>
+
+/**
+ * string_parse_html_anchor:
+ * @line               : Buffer where the <a> tag is stored
+ * @link               : Buffer to store the link URL in
+ * @name               : Buffer to store the link URL in
+ * @link_size          : Size of the link buffer including the NUL-terminator
+ * @name_size          : Size of the name buffer including the NUL-terminator
+ *
+ * Parses an HTML anchor link stored in @line in the form of: <a href="/path/to/url">Title</a>
+ * The buffer pointed to by @link is filled with the URL path the link points to,
+ * and @name is filled with the title portion of the link.
+ *
+ * @return 0 if URL was parsed completely, otherwise 1.
+ **/
+int string_parse_html_anchor(const char *line, char *link, char *name,
+      size_t link_size, size_t name_size)
+{
+   if (!line || !link || !name)
+      return 1;
+
+   memset(link, 0, link_size);
+   memset(name, 0, name_size);
+
+   line = strcasestr(line, "<a href=\"");
+
+   if (!line)
+      return 1;
+
+   line += 9;
+
+   if (line && *line)
+   {
+      if (!*link)
+      {
+         const char *end = strstr(line, "\"");
+
+         if (!end)
+            return 1;
+
+         memcpy(link, line, end - line);
+
+         *(link + (end - line)) = '\0';
+         line += end - line;
+      }
+
+      if (!*name)
+      {
+         const char *start = strstr(line, "\">");
+         const char *end   = start ? strstr(start, "</a>") : NULL;
+
+         if (!start || !end)
+            return 1;
+
+         memcpy(name, start + 2, end - start - 2);
+
+         *(name + (end - start - 2)) = '\0';
+      }
+   }
+
+   return 0;
+}
diff --git a/deps/libretro-common/net/net_ifinfo.c b/deps/libretro-common/net/net_ifinfo.c
new file mode 100644 (file)
index 0000000..6e4d7d7
--- /dev/null
@@ -0,0 +1,420 @@
+/* Copyright  (C) 2010-2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_ifinfo.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+
+#include <string/stdstring.h>
+#include <net/net_compat.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#ifdef _MSC_VER
+#pragma comment(lib, "Iphlpapi")
+#endif
+
+#include <iphlpapi.h>
+
+#elif !defined(VITA) && !defined(GEKKO)
+#if defined(WANT_IFADDRS)
+#include <compat/ifaddrs.h>
+#elif !defined(HAVE_LIBNX) && !defined(_3DS)
+#include <ifaddrs.h>
+#ifndef WIIU
+#include <net/if.h>
+#endif
+#endif
+#endif
+
+#include <net/net_ifinfo.h>
+
+bool net_ifinfo_new(net_ifinfo_t *list)
+{
+#if defined(_WIN32) && !defined(_XBOX)
+   /* Microsoft docs recommend doing it this way. */
+   char buf[512];
+   ULONG result;
+   PIP_ADAPTER_ADDRESSES addr;
+   struct net_ifinfo_entry *entry;
+   size_t                interfaces = 0;
+   ULONG                 flags      = GAA_FLAG_SKIP_ANYCAST
+                                    | GAA_FLAG_SKIP_MULTICAST 
+                                    | GAA_FLAG_SKIP_DNS_SERVER;
+   ULONG                 len        = 15 * 1024;
+   PIP_ADAPTER_ADDRESSES addresses  = (PIP_ADAPTER_ADDRESSES)calloc(1, len);
+
+   list->entries                    = NULL;
+
+   if (!addresses)
+      goto failure;
+
+   result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addresses, &len);
+   if (result == ERROR_BUFFER_OVERFLOW)
+   {
+      PIP_ADAPTER_ADDRESSES new_addresses =
+         (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);
+
+      if (new_addresses)
+      {
+         memset(new_addresses, 0, len);
+
+         addresses = new_addresses;
+         result    = GetAdaptersAddresses(AF_UNSPEC, flags, NULL,
+            addresses, &len);
+      }
+   }
+   if (result != ERROR_SUCCESS)
+      goto failure;
+
+   /* Count the number of valid interfaces first. */
+   addr = addresses;
+
+   do
+   {
+      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;
+
+      if (!unicast_addr)
+         continue;
+      if (addr->OperStatus != IfOperStatusUp)
+         continue;
+
+      do
+      {
+         interfaces++;
+      } while ((unicast_addr = unicast_addr->Next));
+   } while ((addr = addr->Next));
+
+   if (!interfaces)
+      goto failure;
+
+   if (!(list->entries =
+      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries))))
+      goto failure;
+
+   list->size    = 0;
+   /* Now create the entries. */
+   addr          = addresses;
+   entry         = list->entries;
+
+   do
+   {
+      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;
+
+      if (!unicast_addr)
+         continue;
+      if (addr->OperStatus != IfOperStatusUp)
+         continue;
+
+      buf[0] = '\0';
+      if (addr->FriendlyName)
+      {
+         if (!WideCharToMultiByte(CP_UTF8, 0, addr->FriendlyName, -1,
+               buf, sizeof(buf), NULL, NULL))
+            buf[0] = '\0'; /* Empty name on conversion failure. */
+      }
+
+      do
+      {
+         if (getnameinfo_retro(unicast_addr->Address.lpSockaddr,
+               unicast_addr->Address.iSockaddrLength,
+               entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))
+            continue;
+
+         strlcpy(entry->name, buf, sizeof(entry->name));
+
+         if (++list->size >= interfaces)
+            break;
+
+         entry++;
+      } while ((unicast_addr = unicast_addr->Next));
+
+      if (list->size >= interfaces)
+         break;
+   } while ((addr = addr->Next));
+
+   free(addresses);
+
+   return true;
+
+failure:
+   free(addresses);
+   net_ifinfo_free(list);
+
+   return false;
+#elif defined(VITA)
+   SceNetCtlInfo info;
+   if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))
+   {
+      list->size = 0;
+      return false;
+   }
+
+   strlcpy(list->entries[0].name, "lo",        sizeof(list->entries[0].name));
+   strlcpy(list->entries[0].host, "127.0.0.1", sizeof(list->entries[0].host));
+   list->size = 1;
+
+   if (!sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &info))
+   {
+      strlcpy(list->entries[1].name, "wlan", sizeof(list->entries[1].name));
+      strlcpy(list->entries[1].host, info.ip_address,
+         sizeof(list->entries[1].host));
+      list->size++;
+   }
+
+   return true;
+#elif defined(HAVE_LIBNX) || defined(_3DS) || defined(GEKKO)
+   uint32_t addr = 0;
+   if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))
+   {
+      list->size = 0;
+      return false;
+   }
+
+   strlcpy(list->entries[0].name, "lo", sizeof(list->entries[0].name));
+   strlcpy(list->entries[0].host, "127.0.0.1", sizeof(list->entries[0].host));
+   list->size = 1;
+
+#if defined(HAVE_LIBNX)
+   {
+      Result rc = nifmGetCurrentIpAddress(&addr);
+
+      if (!R_SUCCEEDED(rc))
+         return true;
+   }
+#elif defined(_3DS)
+   addr = gethostid();
+#else
+   addr = net_gethostip();
+#endif
+   if (addr)
+   {
+      uint8_t *addr8 = (uint8_t*)&addr;
+      strlcpy(list->entries[1].name,
+#if defined(HAVE_LIBNX)
+         "switch"
+#elif defined(_3DS)
+         "wlan"
+#else
+         "gekko"
+#endif
+      , sizeof(list->entries[1].name));
+      snprintf(list->entries[1].host, sizeof(list->entries[1].host),
+         "%d.%d.%d.%d",
+         (int)addr8[0], (int)addr8[1], (int)addr8[2], (int)addr8[3]);
+      list->size++;
+   }
+
+   return true;
+#else
+   struct ifaddrs *addr;
+   struct net_ifinfo_entry *entry;
+   size_t         interfaces = 0;
+   struct ifaddrs *addresses = NULL;
+
+   list->entries             = NULL;
+
+   if (getifaddrs(&addresses) || !addresses)
+      goto failure;
+
+   /* Count the number of valid interfaces first. */
+   addr                      = addresses;
+
+   do
+   {
+      if (!addr->ifa_addr)
+         continue;
+#ifndef WIIU
+      if (!(addr->ifa_flags & IFF_UP))
+         continue;
+#endif
+
+      switch (addr->ifa_addr->sa_family)
+      {
+         case AF_INET:
+#ifdef HAVE_INET6
+         case AF_INET6:
+#endif
+            interfaces++;
+            break;
+         default:
+            break;
+      }
+   } while ((addr = addr->ifa_next));
+
+   if (!interfaces)
+      goto failure;
+
+   list->entries =
+      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries));
+   if (!list->entries)
+      goto failure;
+   list->size    = 0;
+
+   /* Now create the entries. */
+   addr  = addresses;
+   entry = list->entries;
+
+   do
+   {
+      socklen_t addrlen;
+
+      if (!addr->ifa_addr)
+         continue;
+#ifndef WIIU
+      if (!(addr->ifa_flags & IFF_UP))
+         continue;
+#endif
+
+      switch (addr->ifa_addr->sa_family)
+      {
+         case AF_INET:
+            addrlen = sizeof(struct sockaddr_in);
+            break;
+#ifdef HAVE_INET6
+         case AF_INET6:
+            addrlen = sizeof(struct sockaddr_in6);
+            break;
+#endif
+         default:
+            continue;
+      }
+
+      if (getnameinfo_retro(addr->ifa_addr, addrlen,
+            entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))
+         continue;
+
+      if (addr->ifa_name)
+         strlcpy(entry->name, addr->ifa_name, sizeof(entry->name));
+
+      if (++list->size >= interfaces)
+         break;
+
+      entry++;
+   } while ((addr = addr->ifa_next));
+
+   freeifaddrs(addresses);
+
+   return true;
+
+failure:
+   freeifaddrs(addresses);
+   net_ifinfo_free(list);
+
+   return false;
+#endif
+}
+
+void net_ifinfo_free(net_ifinfo_t *list)
+{
+   free(list->entries);
+
+   list->entries = NULL;
+   list->size    = 0;
+}
+
+bool net_ifinfo_best(const char *dst, void *src, bool ipv6)
+{
+   bool ret = false;
+
+/* TODO/FIXME: Implement for other platforms, if necessary. */
+#if defined(_WIN32) && !defined(_XBOX)
+   if (!ipv6)
+   {
+      /* Courtesy of MiniUPnP: https://github.com/miniupnp/miniupnp */
+      DWORD index;
+#ifdef __WINRT__
+      struct sockaddr_in dst_addr = {0};
+#endif
+      ULONG dst_ip               = (ULONG)inet_addr(dst);
+
+      if (!src)
+         return false;
+      if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY)
+         return false;
+
+#ifdef __WINRT__
+      dst_addr.sin_family      = AF_INET;
+      dst_addr.sin_addr.s_addr = dst_ip;
+      if (GetBestInterfaceEx((struct sockaddr*)&dst_addr, &index) == NO_ERROR)
+#else
+      if (GetBestInterface(dst_ip, &index) == NO_ERROR)
+#endif
+      {
+         /* Microsoft docs recommend doing it this way. */
+         ULONG                 len       = 15 * 1024;
+         PIP_ADAPTER_ADDRESSES addresses =
+            (PIP_ADAPTER_ADDRESSES)calloc(1, len);
+
+         if (addresses)
+         {
+            ULONG flags  = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+               GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
+            ULONG result = GetAdaptersAddresses(AF_INET, flags, NULL,
+               addresses, &len);
+
+            if (result == ERROR_BUFFER_OVERFLOW)
+            {
+               PIP_ADAPTER_ADDRESSES new_addresses =
+                  (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);
+
+               if (new_addresses)
+               {
+                  memset(new_addresses, 0, len);
+
+                  addresses = new_addresses;
+                  result    = GetAdaptersAddresses(AF_INET, flags, NULL,
+                     addresses, &len);
+               }
+            }
+
+            if (result == NO_ERROR)
+            {
+               PIP_ADAPTER_ADDRESSES addr = addresses;
+
+               do
+               {
+                  if (addr->IfIndex == index)
+                  {
+                     if (addr->FirstUnicastAddress)
+                     {
+                        struct sockaddr_in *addr_unicast =
+                           (struct sockaddr_in*)
+                              addr->FirstUnicastAddress->Address.lpSockaddr;
+
+                        memcpy(src, &addr_unicast->sin_addr,
+                           sizeof(addr_unicast->sin_addr));
+
+                        ret = true;
+                     }
+
+                     break;
+                  }
+               } while ((addr = addr->Next));
+            }
+
+            free(addresses);
+         }
+      }
+   }
+#endif
+
+   return ret;
+}
diff --git a/deps/libretro-common/net/net_socket.c b/deps/libretro-common/net/net_socket.c
new file mode 100644 (file)
index 0000000..039a0b6
--- /dev/null
@@ -0,0 +1,858 @@
+/* Copyright  (C) 2010-2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_socket.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+
+#include <features/features_cpu.h>
+
+#include <net/net_socket.h>
+
+int socket_init(void **address, uint16_t port, const char *server,
+      enum socket_type type, int family)
+{
+   char port_buf[6];
+   struct addrinfo hints      = {0};
+   struct addrinfo **addrinfo = (struct addrinfo**)address;
+   struct addrinfo *addr      = NULL;
+
+   if (!family)
+#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)
+      family = AF_INET;
+#else
+      family = AF_UNSPEC;
+#endif
+
+   hints.ai_family = family;
+
+   switch (type)
+   {
+      case SOCKET_TYPE_DATAGRAM:
+         hints.ai_socktype = SOCK_DGRAM;
+         break;
+      case SOCKET_TYPE_STREAM:
+         hints.ai_socktype = SOCK_STREAM;
+         break;
+      default:
+         return -1;
+   }
+
+   if (!server)
+      hints.ai_flags = AI_PASSIVE;
+
+   if (!network_init())
+      return -1;
+
+   snprintf(port_buf, sizeof(port_buf), "%hu", (unsigned short)port);
+   hints.ai_flags |= AI_NUMERICSERV;
+
+   if (getaddrinfo_retro(server, port_buf, &hints, addrinfo))
+      return -1;
+
+   addr = *addrinfo;
+   if (!addr)
+      return -1;
+
+   return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+}
+
+int socket_next(void **address)
+{
+   struct addrinfo **addrinfo = (struct addrinfo**)address;
+   struct addrinfo *addr      = *addrinfo;
+
+   if ((*addrinfo = addr = addr->ai_next))
+      return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+
+   return -1;
+}
+
+ssize_t socket_receive_all_nonblocking(int fd, bool *error,
+      void *data_, size_t size)
+{
+   ssize_t ret = recv(fd, (char*)data_, size, 0);
+
+   if (ret > 0)
+      return ret;
+
+   if (ret < 0 && isagain((int)ret))
+      return 0;
+
+   *error = true;
+   return -1;
+}
+
+bool socket_receive_all_blocking(int fd, void *data_, size_t size)
+{
+   const uint8_t *data = (const uint8_t*)data_;
+
+   while (size)
+   {
+      ssize_t ret = recv(fd, (char*)data, size, 0);
+
+      if (!ret)
+         return false;
+
+      if (ret < 0)
+      {
+         if (!isagain((int)ret))
+            return false;
+      }
+      else
+      {
+         data += ret;
+         size -= ret;
+      }
+   }
+
+   return true;
+}
+
+bool socket_receive_all_blocking_with_timeout(int fd,
+      void *data_, size_t size,
+      int timeout)
+{
+   const uint8_t *data    = (const uint8_t*)data_;
+   retro_time_t  deadline = cpu_features_get_time_usec();
+
+   if (timeout > 0)
+      deadline += (retro_time_t)timeout * 1000;
+   else
+      deadline += 5000000;
+
+   while (size)
+   {
+      ssize_t ret = recv(fd, (char*)data, size, 0);
+
+      if (!ret)
+         return false;
+
+      if (ret < 0)
+      {
+         int _timeout;
+         bool ready = true;
+
+         if (!isagain((int)ret))
+            return false;
+
+         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);
+         if (_timeout <= 0)
+            return false;
+
+         if (!socket_wait(fd, &ready, NULL, _timeout) || !ready)
+            return false;
+      }
+      else
+      {
+         data += ret;
+         size -= ret;
+      }
+   }
+
+   return true;
+}
+
+bool socket_set_block(int fd, bool block)
+{
+#if defined(_WIN32)
+   u_long i = !block;
+
+   return !ioctlsocket(fd, FIONBIO, &i);
+#elif defined(__PS3__) || defined(VITA) || defined(WIIU)
+   int i = !block;
+
+   return !setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(i));
+#elif defined(GEKKO)
+   u32 i = !block;
+
+   return !net_ioctl(fd, FIONBIO, &i);
+#else
+   int flags = fcntl(fd, F_GETFL);
+
+   if (block)
+      flags &= ~O_NONBLOCK;
+   else
+      flags |= O_NONBLOCK;
+
+   return !fcntl(fd, F_SETFL, flags);
+#endif
+}
+
+bool socket_nonblock(int fd)
+{
+   return socket_set_block(fd, false);
+}
+
+int socket_close(int fd)
+{
+#if defined(_WIN32) && !defined(_XBOX360)
+   /* WinSock has headers from the stone age. */
+   return closesocket(fd);
+#elif defined(__PS3__) || defined(WIIU)
+   return socketclose(fd);
+#elif defined(VITA)
+   return sceNetSocketClose(fd);
+#else
+   return close(fd);
+#endif
+}
+
+int socket_select(int nfds, fd_set *readfds, fd_set *writefds,
+      fd_set *errorfds, struct timeval *timeout)
+{
+#if defined(__PS3__)
+   return socketselect(nfds, readfds, writefds, errorfds, timeout);
+#elif defined(VITA)
+   int i, j;
+   fd_set rfds, wfds, efds;
+   int epoll_fd;
+   SceNetEpollEvent *events     = NULL;
+   int              event_count = 0;
+   int              timeout_us  = -1;
+   int              ret         = -1;
+
+   if (nfds < 0 || nfds > 1024)
+      return SCE_NET_ERROR_EINVAL;
+   if (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))
+      return SCE_NET_ERROR_EINVAL;
+
+   epoll_fd = sceNetEpollCreate("socket_select", 0);
+   if (epoll_fd < 0)
+      return SCE_NET_ERROR_ENOMEM;
+
+   FD_ZERO(&rfds);
+   FD_ZERO(&wfds);
+   FD_ZERO(&efds);
+
+   for (i = 0; i < nfds; i++)
+   {
+      if (readfds && FD_ISSET(i, readfds))
+         event_count++;
+      else if (writefds && FD_ISSET(i, writefds))
+         event_count++;
+      else if (errorfds && FD_ISSET(i, errorfds))
+         event_count++;
+   }
+
+#define ALLOC_EVENTS(count) \
+   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
+   if (!events) \
+   { \
+      ret = SCE_NET_ERROR_ENOMEM; \
+      goto done; \
+   }
+
+   if (event_count)
+   {
+      ALLOC_EVENTS(event_count)
+
+      for (i = 0, j = 0; i < nfds && j < event_count; i++)
+      {
+         SceNetEpollEvent *event = &events[j];
+
+         if (readfds && FD_ISSET(i, readfds))
+            event->events |= SCE_NET_EPOLLIN;
+         if (writefds && FD_ISSET(i, writefds))
+            event->events |= SCE_NET_EPOLLOUT;
+
+         if (event->events || (errorfds && FD_ISSET(i, errorfds)))
+         {
+            event->data.fd = i;
+
+            ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
+               i, event);
+            if (ret < 0)
+            {
+               switch (ret)
+               {
+                  case SCE_NET_ERROR_EBADF:
+                  case SCE_NET_ERROR_ENOMEM:
+                     break;
+                  default:
+                     ret = SCE_NET_ERROR_EBADF;
+                     break;
+               }
+               goto done;
+            }
+
+            j++;
+         }
+      }
+
+      memset(events, 0, event_count * sizeof(*events));
+
+      /* Keep a copy of the original sets for lookup later. */
+      if (readfds)
+         memcpy(&rfds, readfds, sizeof(rfds));
+      if (writefds)
+         memcpy(&wfds, writefds, sizeof(wfds));
+      if (errorfds)
+         memcpy(&efds, errorfds, sizeof(efds));
+   }
+   else
+   {
+      /* Necessary to work with epoll wait. */
+      event_count = 1;
+      ALLOC_EVENTS(1)
+   }
+
+#undef ALLOC_EVENTS
+
+   if (readfds)
+      FD_ZERO(readfds);
+   if (writefds)
+      FD_ZERO(writefds);
+   if (errorfds)
+      FD_ZERO(errorfds);
+
+   /* Vita's epoll takes a microsecond timeout parameter. */
+   if (timeout)
+      timeout_us = (int)(timeout->tv_usec + (timeout->tv_sec * 1000000));
+
+   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout_us);
+   if (ret <= 0)
+      goto done;
+
+#define EPOLL_FD_SET(op, in_set, out_set) \
+   if ((event->events & (op)) && FD_ISSET(event->data.fd, (in_set))) \
+   { \
+      FD_SET(event->data.fd, (out_set)); \
+      j++; \
+   }
+
+   for (i = 0, j = 0; i < ret; i++)
+   {
+      SceNetEpollEvent *event = &events[i];
+
+      /* Sanity check */
+      if (event->data.fd < 0 || event->data.fd >= nfds)
+         continue;
+
+      EPOLL_FD_SET(SCE_NET_EPOLLIN,  &rfds, readfds)
+      EPOLL_FD_SET(SCE_NET_EPOLLOUT, &wfds, writefds)
+      EPOLL_FD_SET(SCE_NET_EPOLLERR, &efds, errorfds)
+   }
+
+   ret = j;
+
+#undef EPOLL_FD_SET
+
+done:
+   free(events);
+   sceNetEpollDestroy(epoll_fd);
+
+   return ret;
+#else
+   return select(nfds, readfds, writefds, errorfds, timeout);
+#endif
+}
+
+#ifdef NETWORK_HAVE_POLL
+int socket_poll(struct pollfd *fds, unsigned nfds, int timeout)
+{
+#if defined(_WIN32)
+   return WSAPoll(fds, nfds, timeout);
+#elif defined(VITA)
+   int i, j;
+   int epoll_fd;
+   SceNetEpollEvent *events     = NULL;
+   int              event_count = (int)nfds;
+   int              ret         = -1;
+
+   if (event_count < 0)
+      return SCE_NET_ERROR_EINVAL;
+
+   epoll_fd = sceNetEpollCreate("socket_poll", 0);
+   if (epoll_fd < 0)
+      return SCE_NET_ERROR_ENOMEM;
+
+#define ALLOC_EVENTS(count) \
+   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \
+   if (!events) \
+   { \
+      ret = SCE_NET_ERROR_ENOMEM; \
+      goto done; \
+   }
+
+   if (event_count)
+   {
+      ALLOC_EVENTS(event_count)
+
+      for (i = 0; i < event_count; i++)
+      {
+         struct pollfd    *fd    = &fds[i];
+         SceNetEpollEvent *event = &events[i];
+
+         fd->revents = 0;
+
+         if (fd->fd < 0)
+            continue;
+
+         event->events  = fd->events;
+         event->data.fd = fd->fd;
+
+         ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,
+            fd->fd, event);
+         if (ret < 0)
+            goto done;
+      }
+
+      memset(events, 0, event_count * sizeof(*events));
+   }
+   else
+   {
+      /* Necessary to work with epoll wait. */
+      event_count = 1;
+      ALLOC_EVENTS(1)
+   }
+
+#undef ALLOC_EVENTS
+
+   /* Vita's epoll takes a microsecond timeout parameter. */
+   if (timeout > 0)
+      timeout *= 1000;
+
+   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout);
+   if (ret <= 0)
+      goto done;
+
+   for (i = 0, j = 0; i < ret; i++)
+   {
+      unsigned k;
+      SceNetEpollEvent *event = &events[i];
+
+      /* Sanity check */
+      if (event->data.fd < 0)
+         continue;
+
+      for (k = 0; k < nfds; k++)
+      {
+         struct pollfd *fd = &fds[k];
+
+         if (fd->fd == event->data.fd)
+         {
+            fd->revents = event->events;
+            j++;
+            break;
+         }
+      }
+   }
+
+   ret = j;
+
+done:
+   free(events);
+   sceNetEpollDestroy(epoll_fd);
+
+   return ret;
+#elif defined(_3DS)
+   int i;
+   int timeout_quotient;
+   int timeout_remainder;
+   int ret = -1;
+
+#define TIMEOUT_DIVISOR 100
+   if (timeout <= TIMEOUT_DIVISOR)
+      return poll(fds, nfds, timeout);
+
+   timeout_quotient = timeout / TIMEOUT_DIVISOR;
+   for (i = 0; i < timeout_quotient; i++)
+   {
+      ret = poll(fds, nfds, TIMEOUT_DIVISOR);
+
+      /* Success or error. */
+      if (ret)
+         return ret;
+   }
+
+   timeout_remainder = timeout % TIMEOUT_DIVISOR;
+   if (timeout_remainder)
+      ret = poll(fds, nfds, timeout_remainder);
+
+   return ret;
+#undef TIMEOUT_DIVISOR
+
+#elif defined(GEKKO)
+   return net_poll(fds, nfds, timeout);
+#else
+   return poll(fds, nfds, timeout);
+#endif
+}
+#endif
+
+bool socket_wait(int fd, bool *rd, bool *wr, int timeout)
+{
+#ifdef NETWORK_HAVE_POLL
+   struct pollfd fds = {0};
+
+   NET_POLL_FD(fd, &fds);
+
+   if (rd && *rd)
+   {
+      NET_POLL_EVENT(POLLIN, &fds);
+      *rd = false;
+   }
+   if (wr && *wr)
+   {
+      NET_POLL_EVENT(POLLOUT, &fds);
+      *wr = false;
+   }
+
+   if (socket_poll(&fds, 1, timeout) < 0)
+      return false;
+
+   if (rd && NET_POLL_HAS_EVENT(POLLIN, &fds))
+      *rd = true;
+   if (wr && NET_POLL_HAS_EVENT(POLLOUT, &fds))
+      *wr = true;
+
+   return !NET_POLL_HAS_EVENT((POLLERR | POLLNVAL), &fds);
+#else
+   fd_set rfd, wfd, efd;
+   struct timeval tv, *ptv = NULL;
+
+   FD_ZERO(&rfd);
+   FD_ZERO(&wfd);
+   FD_ZERO(&efd);
+
+   if (rd && *rd)
+   {
+      FD_SET(fd, &rfd);
+      *rd = false;
+   }
+   if (wr && *wr)
+   {
+      FD_SET(fd, &wfd);
+      *wr = false;
+   }
+   FD_SET(fd, &efd);
+
+   if (timeout >= 0)
+   {
+      tv.tv_sec  = (unsigned)timeout / 1000;
+      tv.tv_usec = ((unsigned)timeout % 1000) * 1000;
+      ptv = &tv;
+   }
+
+   if (socket_select(fd + 1, &rfd, &wfd, &efd, ptv) < 0)
+      return false;
+
+   if (rd && FD_ISSET(fd, &rfd))
+      *rd = true;
+   if (wr && FD_ISSET(fd, &wfd))
+      *wr = true;
+
+   return !FD_ISSET(fd, &efd);
+#endif
+}
+
+bool socket_send_all_blocking(int fd, const void *data_, size_t size,
+      bool no_signal)
+{
+   const uint8_t *data = (const uint8_t*)data_;
+   int           flags = no_signal ? MSG_NOSIGNAL : 0;
+
+   while (size)
+   {
+      ssize_t ret = send(fd, (const char*)data, size, flags);
+
+      if (!ret)
+         continue;
+
+      if (ret < 0)
+      {
+         if (!isagain((int)ret))
+            return false;
+      }
+      else
+      {
+         data += ret;
+         size -= ret;
+      }
+   }
+
+   return true;
+}
+
+bool socket_send_all_blocking_with_timeout(int fd,
+      const void *data_, size_t size,
+      int timeout, bool no_signal)
+{
+   const uint8_t *data    = (const uint8_t*)data_;
+   int           flags    = no_signal ? MSG_NOSIGNAL : 0;
+   retro_time_t  deadline = cpu_features_get_time_usec();
+
+   if (timeout > 0)
+      deadline += (retro_time_t)timeout * 1000;
+   else
+      deadline += 5000000;
+
+   while (size)
+   {
+      ssize_t ret = send(fd, (const char*)data, size, flags);
+
+      if (!ret)
+         continue;
+
+      if (ret < 0)
+      {
+         int _timeout;
+         bool ready = true;
+
+         if (!isagain((int)ret))
+            return false;
+
+         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);
+         if (_timeout <= 0)
+            return false;
+
+         if (!socket_wait(fd, NULL, &ready, _timeout) || !ready)
+            return false;
+      }
+      else
+      {
+         data += ret;
+         size -= ret;
+      }
+   }
+
+   return true;
+}
+
+ssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t size,
+      bool no_signal)
+{
+   const uint8_t *data = (const uint8_t*)data_;
+   int           flags = no_signal ? MSG_NOSIGNAL : 0;
+
+   while (size)
+   {
+      ssize_t ret = send(fd, (const char*)data, size, flags);
+
+      if (!ret)
+         break;
+
+      if (ret < 0)
+      {
+         if (isagain((int)ret))
+            break;
+
+         return -1;
+      }
+      else
+      {
+         data += ret;
+         size -= ret;
+      }
+   }
+
+   return (ssize_t)((size_t)data - (size_t)data_);
+}
+
+bool socket_bind(int fd, void *data)
+{
+   struct addrinfo *addr = (struct addrinfo*)data;
+
+   {
+      int on = 1;
+
+      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+         (char*)&on, sizeof(on));
+   }
+
+   return !bind(fd, addr->ai_addr, addr->ai_addrlen);
+}
+
+int socket_connect(int fd, void *data)
+{
+   struct addrinfo *addr = (struct addrinfo*)data;
+
+#ifdef WIIU
+   {
+      int op = 1;
+
+      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));
+
+      if (addr->ai_socktype == SOCK_STREAM)
+      {
+         int recvsz = WIIU_RCVBUF;
+         int sendsz = WIIU_SNDBUF;
+
+         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));
+         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &op, sizeof(op));
+         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));
+         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));
+      }
+   }
+#endif
+
+   return connect(fd, addr->ai_addr, addr->ai_addrlen);
+}
+
+bool socket_connect_with_timeout(int fd, void *data, int timeout)
+{
+   int res;
+   struct addrinfo *addr = (struct addrinfo*)data;
+
+   if (!socket_nonblock(fd))
+      return false;
+
+#ifdef WIIU
+   {
+      int op = 1;
+
+      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));
+
+      if (addr->ai_socktype == SOCK_STREAM)
+      {
+         int recvsz = WIIU_RCVBUF;
+         int sendsz = WIIU_SNDBUF;
+
+         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));
+         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &op, sizeof(op));
+         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));
+         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));
+      }
+   }
+#endif
+
+   res = connect(fd, addr->ai_addr, addr->ai_addrlen);
+   if (res)
+   {
+      bool ready = true;
+
+      if (!isinprogress(res) && !isagain(res))
+         return false;
+
+      if (timeout <= 0)
+         timeout = 5000;
+
+      if (!socket_wait(fd, NULL, &ready, timeout) || !ready)
+         return false;
+   }
+
+#if defined(GEKKO)
+   /* libogc does not have getsockopt implemented */
+   res = connect(fd, addr->ai_addr, addr->ai_addrlen);
+   if (res < 0 && -res != EISCONN)
+      return false;
+#elif defined(_3DS)
+   /* libctru getsockopt does not return expected value */
+   if ((connect(fd, addr->ai_addr, addr->ai_addrlen) < 0) && errno != EISCONN)
+      return false;
+#elif defined(WIIU)
+   /* On WiiU, getsockopt() returns -1 and sets lastsocketerr() (Wii's
+    * equivalent to errno) to 16. */
+   if ((connect(fd, addr->ai_addr, addr->ai_addrlen) == -1)
+         && socketlasterr() != SO_EISCONN)
+      return false;
+#else
+   {
+      int       error = -1;
+      socklen_t errsz = sizeof(error);
+
+      getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&error, &errsz);
+      if (error)
+         return false;
+   }
+#endif
+
+   return true;
+}
+
+int socket_create(
+      const char *name,
+      enum socket_domain   domain_type,
+      enum socket_type     socket_type,
+      enum socket_protocol protocol_type)
+{
+   int domain   = 0;
+   int type     = 0;
+   int protocol = 0;
+
+   switch (domain_type)
+   {
+      case SOCKET_DOMAIN_INET:
+         domain = AF_INET;
+         break;
+      default:
+         break;
+   }
+
+   switch (socket_type)
+   {
+      case SOCKET_TYPE_DATAGRAM:
+         type = SOCK_DGRAM;
+         break;
+      case SOCKET_TYPE_STREAM:
+         type = SOCK_STREAM;
+         break;
+      case SOCKET_TYPE_SEQPACKET:
+      default:
+         /* TODO/FIXME - implement */
+         break;
+   }
+
+   switch (protocol_type)
+   {
+      case SOCKET_PROTOCOL_TCP:
+         protocol = IPPROTO_TCP;
+         break;
+      case SOCKET_PROTOCOL_UDP:
+         protocol = IPPROTO_UDP;
+         break;
+      case SOCKET_PROTOCOL_NONE:
+      default:
+         break;
+   }
+
+#ifdef VITA
+   return sceNetSocket(name, domain, type, protocol);
+#else
+   return socket(domain, type, protocol);
+#endif
+}
+
+void socket_set_target(void *data, socket_target_t *in_addr)
+{
+   struct sockaddr_in *out_target = (struct sockaddr_in*)data;
+
+#ifdef GEKKO
+   out_target->sin_len          = 8;
+#endif
+   switch (in_addr->domain)
+   {
+      case SOCKET_DOMAIN_INET:
+         out_target->sin_family = AF_INET;
+         break;
+      default:
+         out_target->sin_family = 0;
+         break;
+   }
+   out_target->sin_port         = htons(in_addr->port);
+   inet_pton(AF_INET, in_addr->server, &out_target->sin_addr);
+}
diff --git a/deps/libretro-common/net/net_socket_ssl_bear.c b/deps/libretro-common/net/net_socket_ssl_bear.c
new file mode 100644 (file)
index 0000000..3892e79
--- /dev/null
@@ -0,0 +1,381 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_socket.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <net/net_socket_ssl.h>
+#include <net/net_socket.h>
+#include <encodings/base64.h>
+#include <streams/file_stream.h>
+#include <string/stdstring.h>
+
+#include "../../deps/bearssl-0.6/inc/bearssl.h"
+
+struct ssl_state
+{
+   int fd;
+   br_ssl_client_context sc;
+   br_x509_minimal_context xc;
+   uint8_t iobuf[BR_SSL_BUFSIZE_BIDI];
+};
+
+/* TODO/FIXME - static global variables */
+static br_x509_trust_anchor TAs[500] = {};
+static size_t TAs_NUM = 0;
+
+static uint8_t* current_vdn;
+static size_t current_vdn_size;
+
+static uint8_t* blobdup(const void * src, size_t len)
+{
+   uint8_t * ret = malloc(len);
+   memcpy(ret, src, len);
+   return ret;
+}
+static void vdn_append(void* dest_ctx, const void * src, size_t len)
+{
+   current_vdn = realloc(current_vdn, current_vdn_size + len);
+   memcpy(current_vdn+current_vdn_size, src, len);
+   current_vdn_size += len;
+}
+
+static bool append_cert_x509(void* x509, size_t len)
+{
+   br_x509_pkey* pk;
+   br_x509_decoder_context dc;
+   br_x509_trust_anchor* ta = &TAs[TAs_NUM];
+   
+   current_vdn              = NULL;
+   current_vdn_size         = 0;
+   
+   br_x509_decoder_init(&dc, vdn_append, NULL);
+   br_x509_decoder_push(&dc, x509, len);
+   pk                       = br_x509_decoder_get_pkey(&dc);
+   if (!pk || !br_x509_decoder_isCA(&dc))
+      return false;
+   
+   ta->dn.len               = current_vdn_size;
+   ta->dn.data              = current_vdn;
+   ta->flags                = BR_X509_TA_CA;
+   
+   switch (pk->key_type)
+   {
+      case BR_KEYTYPE_RSA:
+         ta->pkey.key_type     = BR_KEYTYPE_RSA;
+         ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;
+         ta->pkey.key.rsa.n    = blobdup(pk->key.rsa.n, pk->key.rsa.nlen);
+         ta->pkey.key.rsa.elen = pk->key.rsa.elen;
+         ta->pkey.key.rsa.e    = blobdup(pk->key.rsa.e, pk->key.rsa.elen);
+         break;
+      case BR_KEYTYPE_EC:
+         ta->pkey.key_type     = BR_KEYTYPE_EC;
+         ta->pkey.key.ec.curve = pk->key.ec.curve;
+         ta->pkey.key.ec.qlen  = pk->key.ec.qlen;
+         ta->pkey.key.ec.q     = blobdup(pk->key.ec.q, pk->key.ec.qlen);
+         break;
+      default:
+         return false;
+   }
+   
+   TAs_NUM++;
+   return true;
+}
+
+static char* delete_linebreaks(char* in)
+{
+   char* iter_in;
+   char* iter_out;
+   while (*in == '\n')
+      in++;
+
+   iter_in = in;
+
+   while (*iter_in != '\n' && *iter_in != '\0')
+      iter_in++;
+   iter_out = iter_in;
+   while (*iter_in != '\0')
+   {
+      while (*iter_in == '\n')
+         iter_in++;
+      *iter_out++ = *iter_in++;
+   }
+
+   return in;
+}
+
+/* this rearranges its input, it's easier to implement 
+ * that way and caller doesn't need it anymore anyways */
+static void append_certs_pem_x509(char * certs_pem)
+{
+   void * cert_bin;
+   int cert_bin_len;
+   char *cert     = certs_pem;
+   char *cert_end = certs_pem;
+
+   for (;;)
+   {
+      cert      = strstr(cert_end, "-----BEGIN CERTIFICATE-----");
+      if (!cert)
+         break;
+      cert     += STRLEN_CONST("-----BEGIN CERTIFICATE-----");
+      cert_end  = strstr(cert, "-----END CERTIFICATE-----");
+
+      *cert_end = '\0';
+      cert      = delete_linebreaks(cert);
+
+      cert_bin  = unbase64(cert, cert_end-cert, &cert_bin_len);
+      append_cert_x509(cert_bin, cert_bin_len);
+      free(cert_bin);
+
+      cert_end++; /* skip the NUL we just added */
+   }
+}
+
+/* TODO: not thread safe, rthreads doesn't provide any 
+ * statically allocatable mutex/etc */
+static void initialize(void)
+{
+   void* certs_pem;
+   if (TAs_NUM)
+      return;
+   /* filestream_read_file appends a NUL */
+   filestream_read_file("/etc/ssl/certs/ca-certificates.crt", &certs_pem, NULL);
+   append_certs_pem_x509((char*)certs_pem);
+   free(certs_pem);
+}
+
+void* ssl_socket_init(int fd, const char *domain)
+{
+   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));
+
+   initialize();
+
+   br_ssl_client_init_full(&state->sc, &state->xc, TAs, TAs_NUM);
+   br_ssl_engine_set_buffer(&state->sc.eng,
+         state->iobuf, sizeof(state->iobuf), true);
+   br_ssl_client_reset(&state->sc, domain, false);
+
+   state->fd = fd;
+   return state;
+}
+
+static bool process_inner(struct ssl_state *state, bool blocking)
+{
+   bool dummy;
+   size_t buflen;
+   ssize_t bytes;
+   uint8_t *buf = br_ssl_engine_sendrec_buf(&state->sc.eng, &buflen);
+
+   if (buflen)
+   {
+      if (blocking)
+         bytes = (socket_send_all_blocking(state->fd, buf, buflen, true) 
+               ? buflen 
+               : -1);
+      else
+         bytes = socket_send_all_nonblocking(state->fd, buf, buflen, true);
+
+      if (bytes > 0)
+         br_ssl_engine_sendrec_ack(&state->sc.eng, bytes);
+      if (bytes < 0)
+         return false;
+      /* if we did something, return immediately so we 
+       * don't try to read if Bear still wants to send */
+      return true; 
+   }
+
+   buf = br_ssl_engine_recvrec_buf(&state->sc.eng, &buflen);
+   if (buflen)
+   {
+      /* if the socket is blocking, socket_receive_all_nonblocking blocks,
+       * but only to read at least 1 byte which is exactly what we want */
+      bytes = socket_receive_all_nonblocking(state->fd, &dummy, buf, buflen);
+      if (bytes > 0)
+         br_ssl_engine_recvrec_ack(&state->sc.eng, bytes);
+      if (bytes < 0)
+         return false;
+   }
+
+   return true;
+}
+
+int ssl_socket_connect(void *state_data,
+      void *data, bool timeout_enable, bool nonblock)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   unsigned bearstate;
+
+   if (timeout_enable)
+   {
+      if (!socket_connect_with_timeout(state->fd, data, 5000))
+         return -1;
+      /* socket_connect_with_timeout makes the socket non-blocking. */
+      if (!socket_set_block(state->fd, true))
+         return -1;
+   }
+   else
+   {
+      if (socket_connect(state->fd, data))
+         return -1;
+   }
+
+   for (;;)
+   {
+      if (!process_inner(state, true))
+         return -1;
+
+      bearstate = br_ssl_engine_current_state(&state->sc.eng);
+      if (bearstate & BR_SSL_SENDAPP)
+         break; /* handshake done */
+      if (bearstate & BR_SSL_CLOSED)
+         return -1; /* failed */
+   }
+
+   return 1;
+}
+
+ssize_t ssl_socket_receive_all_nonblocking(void *state_data,
+      bool *error, void *data_, size_t size)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   uint8_t *         bear_data;
+   size_t            bear_data_size;
+
+   socket_set_block(state->fd, false);
+
+   if (!process_inner(state, false))
+   {
+      *error = true;
+      return -1;
+   }
+   
+   bear_data = br_ssl_engine_recvapp_buf(&state->sc.eng, &bear_data_size);
+   if (bear_data_size > size) bear_data_size = size;
+   memcpy(data_, bear_data, bear_data_size);
+   if (bear_data_size)
+      br_ssl_engine_recvapp_ack(&state->sc.eng, bear_data_size);
+   
+   return bear_data_size;
+}
+
+int ssl_socket_receive_all_blocking(void *state_data,
+      void *data_, size_t size)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   uint8_t           *data = (uint8_t*)data_;
+   uint8_t *         bear_data;
+   size_t            bear_data_size;
+
+   socket_set_block(state->fd, true);
+
+   for (;;)
+   {
+      bear_data = br_ssl_engine_recvapp_buf(&state->sc.eng, &bear_data_size);
+      if (bear_data_size > size)
+         bear_data_size = size;
+      memcpy(data, bear_data, bear_data_size);
+      if (bear_data_size)
+         br_ssl_engine_recvapp_ack(&state->sc.eng, bear_data_size);
+      data += bear_data_size;
+      size -= bear_data_size;
+
+      if (size)
+         process_inner(state, true);
+      else
+         break;
+   }
+   return 1;
+}
+
+int ssl_socket_send_all_blocking(void *state_data,
+      const void *data_, size_t size, bool no_signal)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   const     uint8_t *data = (const uint8_t*)data_;
+   uint8_t *         bear_data;
+   size_t            bear_data_size;
+
+   socket_set_block(state->fd, true);
+
+   for (;;)
+   {
+      bear_data = br_ssl_engine_sendapp_buf(&state->sc.eng, &bear_data_size);
+      if (bear_data_size > size)
+         bear_data_size = size;
+      memcpy(bear_data, data_, bear_data_size);
+      if (bear_data_size)
+         br_ssl_engine_sendapp_ack(&state->sc.eng, bear_data_size);
+      data += bear_data_size;
+      size -= bear_data_size;
+
+      if (size)
+         process_inner(state, true);
+      else
+         break;
+   }
+
+   br_ssl_engine_flush(&state->sc.eng, false);
+   process_inner(state, false);
+   return 1;
+}
+
+ssize_t ssl_socket_send_all_nonblocking(void *state_data,
+      const void *data_, size_t size, bool no_signal)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   uint8_t *         bear_data;
+   size_t            bear_data_size;
+
+   socket_set_block(state->fd, false);
+
+   bear_data = br_ssl_engine_sendapp_buf(&state->sc.eng, &bear_data_size);
+   if (bear_data_size > size)
+      bear_data_size = size;
+   memcpy(bear_data, data_, bear_data_size);
+   if (bear_data_size)
+   {
+      br_ssl_engine_sendapp_ack(&state->sc.eng, bear_data_size);
+      br_ssl_engine_flush(&state->sc.eng, false);
+   }
+
+   if (!process_inner(state, false))
+      return -1;
+
+   return bear_data_size;
+}
+
+void ssl_socket_close(void *state_data)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+
+   br_ssl_engine_close(&state->sc.eng);
+   process_inner(state, false); /* send close notification */
+   socket_close(state->fd);     /* but immediately close socket 
+                                   and don't worry about recipient 
+                                   getting our message */
+}
+
+void ssl_socket_free(void *state_data)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   /* BearSSL does zero allocations of its own, 
+    * so other than this struct, there is nothing to free */
+   free(state);
+}
diff --git a/deps/libretro-common/net/net_socket_ssl_mbed.c b/deps/libretro-common/net/net_socket_ssl_mbed.c
new file mode 100644 (file)
index 0000000..48bed20
--- /dev/null
@@ -0,0 +1,290 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_socket.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <string.h>
+#include <net/net_compat.h>
+#include <net/net_socket.h>
+#include <net/net_socket_ssl.h>
+
+#if defined(HAVE_BUILTINMBEDTLS)
+#include "../../deps/mbedtls/mbedtls/config.h"
+#include "../../deps/mbedtls/mbedtls/certs.h"
+#include "../../deps/mbedtls/mbedtls/debug.h"
+#include "../../deps/mbedtls/mbedtls/platform.h"
+#include "../../deps/mbedtls/mbedtls/net_sockets.h"
+#include "../../deps/mbedtls/mbedtls/ssl.h"
+#include "../../deps/mbedtls/mbedtls/ctr_drbg.h"
+#include "../../deps/mbedtls/mbedtls/entropy.h"
+#else
+#include <mbedtls/config.h>
+#include <mbedtls/certs.h>
+#include <mbedtls/debug.h>
+#include <mbedtls/platform.h>
+#include <mbedtls/net_sockets.h>
+#include <mbedtls/ssl.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+#endif
+
+/* Not part of the mbedtls upstream source */
+#include "../../deps/mbedtls/cacert.h"
+
+#define DEBUG_LEVEL 0
+
+struct ssl_state
+{
+   mbedtls_net_context net_ctx;
+   mbedtls_ssl_context ctx;
+   mbedtls_entropy_context entropy;
+   mbedtls_ctr_drbg_context ctr_drbg;
+   mbedtls_ssl_config conf;
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+   mbedtls_x509_crt ca;
+#endif
+  const char *domain;
+};
+
+static void ssl_debug(void *ctx, int level,
+      const char *file, int line,
+      const char *str)
+{
+   fprintf((FILE*)ctx, "%s:%04d: %s", file, line, str);
+   fflush((FILE*)ctx);
+}
+
+void* ssl_socket_init(int fd, const char *domain)
+{
+   static const char *pers = "libretro";
+   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));
+
+   state->domain           = domain;
+
+#if defined(MBEDTLS_DEBUG_C)
+   mbedtls_debug_set_threshold(DEBUG_LEVEL);
+#endif
+
+   mbedtls_net_init(&state->net_ctx);
+   mbedtls_ssl_init(&state->ctx);
+   mbedtls_ssl_config_init(&state->conf);
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+   mbedtls_x509_crt_init(&state->ca);
+#endif
+   mbedtls_ctr_drbg_init(&state->ctr_drbg);
+   mbedtls_entropy_init(&state->entropy);
+
+   state->net_ctx.fd = fd;
+
+   if (mbedtls_ctr_drbg_seed(&state->ctr_drbg, mbedtls_entropy_func, &state->entropy, (const unsigned char*)pers, strlen(pers)) != 0)
+      goto error;
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+   if (mbedtls_x509_crt_parse(&state->ca, (const unsigned char*)cacert_pem, sizeof(cacert_pem) / sizeof(cacert_pem[0])) < 0)
+      goto error;
+#endif
+
+   return state;
+
+error:
+   if (state)
+      free(state);
+   return NULL;
+}
+
+int ssl_socket_connect(void *state_data,
+      void *data, bool timeout_enable, bool nonblock)
+{
+   int ret, flags;
+   struct ssl_state *state = (struct ssl_state*)state_data;
+
+   if (timeout_enable)
+   {
+      if (!socket_connect_with_timeout(state->net_ctx.fd, data, 5000))
+         return -1;
+      /* socket_connect_with_timeout makes the socket non-blocking. */
+      if (!socket_set_block(state->net_ctx.fd, true))
+         return -1;
+   }
+   else
+   {
+      if (socket_connect(state->net_ctx.fd, data))
+         return -1;
+   }
+
+   if (mbedtls_ssl_config_defaults(&state->conf,
+               MBEDTLS_SSL_IS_CLIENT,
+               MBEDTLS_SSL_TRANSPORT_STREAM,
+               MBEDTLS_SSL_PRESET_DEFAULT) != 0)
+      return -1;
+
+   mbedtls_ssl_conf_authmode(&state->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+   mbedtls_ssl_conf_ca_chain(&state->conf, &state->ca, NULL);
+   mbedtls_ssl_conf_rng(&state->conf, mbedtls_ctr_drbg_random, &state->ctr_drbg);
+   mbedtls_ssl_conf_dbg(&state->conf, ssl_debug, stderr);
+
+   if (mbedtls_ssl_setup(&state->ctx, &state->conf) != 0)
+      return -1;
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+   if (mbedtls_ssl_set_hostname(&state->ctx, state->domain) != 0)
+      return -1;
+#endif
+
+   mbedtls_ssl_set_bio(&state->ctx, &state->net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL);
+
+   while ((ret = mbedtls_ssl_handshake(&state->ctx)) != 0)
+   {
+      if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+         return -1;
+   }
+
+   if ((flags = mbedtls_ssl_get_verify_result(&state->ctx)) != 0)
+   {
+      char vrfy_buf[512];
+      mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
+   }
+
+   return state->net_ctx.fd;
+}
+
+ssize_t ssl_socket_receive_all_nonblocking(void *state_data,
+      bool *error, void *data_, size_t size)
+{
+   ssize_t         ret;
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   const uint8_t     *data = (const uint8_t*)data_;
+   /* mbedtls_ssl_read wants non-const data but it only reads it, so this cast is safe */
+
+   mbedtls_net_set_nonblock(&state->net_ctx);
+
+   ret = mbedtls_ssl_read(&state->ctx, (unsigned char*)data, size);
+
+   if (ret > 0)
+      return ret;
+
+   if (ret == 0)
+   {
+      /* Socket closed */
+      *error = true;
+      return -1;
+   }
+
+   if (isagain((int)ret) || ret == MBEDTLS_ERR_SSL_WANT_READ)
+      return 0;
+
+   *error = true;
+   return -1;
+}
+
+int ssl_socket_receive_all_blocking(void *state_data,
+      void *data_, size_t size)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   const uint8_t     *data = (const uint8_t*)data_;
+
+   mbedtls_net_set_block(&state->net_ctx);
+
+   for (;;)
+   {
+      /* mbedtls_ssl_read wants non-const data but it only reads it, 
+       * so this cast is safe */
+      int ret = mbedtls_ssl_read(&state->ctx, (unsigned char*)data, size);
+
+      if (  ret == MBEDTLS_ERR_SSL_WANT_READ || 
+            ret == MBEDTLS_ERR_SSL_WANT_WRITE)
+         continue;
+
+      if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
+         break;
+
+      if (ret == 0)
+         break; /* normal EOF */
+
+      if (ret < 0)
+         return -1;
+   }
+
+   return 1;
+}
+
+int ssl_socket_send_all_blocking(void *state_data,
+      const void *data_, size_t size, bool no_signal)
+{
+   int ret;
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   const     uint8_t *data = (const uint8_t*)data_;
+
+   mbedtls_net_set_block(&state->net_ctx);
+
+   while ((ret = mbedtls_ssl_write(&state->ctx, data, size)) <= 0)
+   {
+      if (  ret != MBEDTLS_ERR_SSL_WANT_READ && 
+            ret != MBEDTLS_ERR_SSL_WANT_WRITE)
+         return false;
+   }
+
+   return true;
+}
+
+ssize_t ssl_socket_send_all_nonblocking(void *state_data,
+      const void *data_, size_t size, bool no_signal)
+{
+   int ret;
+   ssize_t            sent = size;
+   struct ssl_state *state = (struct ssl_state*)state_data;
+   const uint8_t     *data = (const uint8_t*)data_;
+
+   mbedtls_net_set_nonblock(&state->net_ctx);
+
+   ret = mbedtls_ssl_write(&state->ctx, data, size);
+
+   if (ret <= 0)
+      return -1;
+
+   return sent;
+}
+
+void ssl_socket_close(void *state_data)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+
+   mbedtls_ssl_close_notify(&state->ctx);
+
+   socket_close(state->net_ctx.fd);
+}
+
+void ssl_socket_free(void *state_data)
+{
+   struct ssl_state *state = (struct ssl_state*)state_data;
+
+   if (!state)
+      return;
+
+   mbedtls_ssl_free(&state->ctx);
+   mbedtls_ssl_config_free(&state->conf);
+   mbedtls_ctr_drbg_free(&state->ctr_drbg);
+   mbedtls_entropy_free(&state->entropy);
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+   mbedtls_x509_crt_free(&state->ca);
+#endif
+
+   free(state);
+}
diff --git a/deps/libretro-common/playlists/label_sanitization.c b/deps/libretro-common/playlists/label_sanitization.c
new file mode 100644 (file)
index 0000000..50a95ee
--- /dev/null
@@ -0,0 +1,209 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (label_sanitization.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <playlists/label_sanitization.h>
+#include <compat/strl.h>
+#include <retro_miscellaneous.h>
+#include <string/stdstring.h>
+#include <string.h>
+
+#define DISC_STRINGS_LENGTH   3
+#define REGION_STRINGS_LENGTH 20
+
+const char *disc_strings[DISC_STRINGS_LENGTH] = {
+   "(CD",
+   "(Disc",
+   "(Disk"
+};
+
+/*
+ * We'll use the standard No-Intro regions for now.
+ */
+const char *region_strings[REGION_STRINGS_LENGTH] = {
+   "(Australia)", /* Don’t use with Europe */
+   "(Brazil)",
+   "(Canada)",    /* Don’t use with USA */
+   "(China)",
+   "(France)",
+   "(Germany)",
+   "(Hong Kong)",
+   "(Italy)",
+   "(Japan)",
+   "(Korea)",
+   "(Netherlands)",
+   "(Spain)",
+   "(Sweden)",
+   "(USA)",       /* Includes Canada */
+   "(World)",
+   "(Europe)",    /* Includes Australia */
+   "(Asia)",
+   "(Japan, USA)",
+   "(Japan, Europe)",
+   "(USA, Europe)"
+};
+
+/**
+ * label_sanitize:
+ *
+ * NOTE: Does not work with nested blocks.
+ **/
+void label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*))
+{
+   bool copy = true;
+   int rindex = 0;
+   int lindex = 0;
+   char new_label[PATH_MAX_LENGTH];
+
+   for (; lindex < PATH_MAX_LENGTH && label[lindex] != '\0'; lindex++)
+   {
+      if (copy)
+      {
+         /* check for the start of the range */
+         if ((*left)(&label[lindex]))
+            copy                = false;
+         else
+         {
+            const bool whitespace = label[lindex] == ' ' && (rindex == 0 || new_label[rindex - 1] == ' ');
+
+            /* Simplify consecutive whitespaces */
+            if (!whitespace)
+               new_label[rindex++] = label[lindex];
+         }
+      }
+      else if ((*right)(&label[lindex]))
+         copy = true;
+   }
+
+   /* Trim trailing whitespace */
+   if (rindex > 0 && new_label[rindex - 1] == ' ')
+      new_label[rindex - 1] = '\0';
+   else
+      new_label[rindex] = '\0';
+
+   strlcpy(label, new_label, PATH_MAX_LENGTH);
+}
+
+static bool left_parens(char *left)
+{
+   return left[0] == '(';
+}
+
+static bool right_parens(char *right)
+{
+   return right[0] == ')';
+}
+
+static bool left_brackets(char *left)
+{
+   return left[0] == '[';
+}
+
+static bool right_brackets(char *right)
+{
+   return right[0] == ']';
+}
+
+static bool left_parens_or_brackets(char *left)
+{
+   return left[0] == '(' || left[0] == '[';
+}
+
+static bool right_parens_or_brackets(char *right)
+{
+   return right[0] == ')' || right[0] == ']';
+}
+
+static bool left_exclusion(char *left,
+      const char **strings, const size_t strings_count)
+{
+   unsigned i;
+   char exclusion_string[32];
+   char comparison_string[32];
+
+   strlcpy(exclusion_string, left, sizeof(exclusion_string));
+   string_to_upper(exclusion_string);
+
+   for (i = 0; i < (unsigned)strings_count; i++)
+   {
+      strlcpy(comparison_string, strings[i], sizeof(comparison_string));
+      string_to_upper(comparison_string);
+
+      if (string_starts_with(exclusion_string,
+               comparison_string))
+         return true;
+   }
+
+   return false;
+}
+
+static bool left_parens_or_brackets_excluding_region(char *left)
+{
+   return left_parens_or_brackets(left)
+      && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH);
+}
+
+static bool left_parens_or_brackets_excluding_disc(char *left)
+{
+   return left_parens_or_brackets(left)
+      && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
+}
+
+static bool left_parens_or_brackets_excluding_region_or_disc(char *left)
+{
+   return left_parens_or_brackets(left)
+      && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH)
+      && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
+}
+
+void label_remove_parens(char *label)
+{
+   label_sanitize(label, left_parens, right_parens);
+}
+
+void label_remove_brackets(char *label)
+{
+   label_sanitize(label, left_brackets, right_brackets);
+}
+
+void label_remove_parens_and_brackets(char *label)
+{
+   label_sanitize(label, left_parens_or_brackets,
+         right_parens_or_brackets);
+}
+
+void label_keep_region(char *label)
+{
+   label_sanitize(label, left_parens_or_brackets_excluding_region,
+         right_parens_or_brackets);
+}
+
+void label_keep_disc(char *label)
+{
+   label_sanitize(label, left_parens_or_brackets_excluding_disc,
+         right_parens_or_brackets);
+}
+
+void label_keep_region_and_disc(char *label)
+{
+   label_sanitize(label, left_parens_or_brackets_excluding_region_or_disc,
+         right_parens_or_brackets);
+}
diff --git a/deps/libretro-common/queues/fifo_queue.c b/deps/libretro-common/queues/fifo_queue.c
new file mode 100644 (file)
index 0000000..7e3849f
--- /dev/null
@@ -0,0 +1,126 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fifo_queue.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <retro_common_api.h>
+#include <retro_inline.h>
+#include <boolean.h>
+
+#include <queues/fifo_queue.h>
+
+static bool fifo_initialize_internal(fifo_buffer_t *buf, size_t size)
+{
+   uint8_t *buffer    = (uint8_t*)calloc(1, size + 1);
+
+   if (!buffer)
+      return false;
+
+   buf->buffer        = buffer;
+   buf->size          = size + 1;
+   buf->first         = 0;
+   buf->end           = 0;
+
+   return true;
+}
+
+bool fifo_initialize(fifo_buffer_t *buf, size_t size)
+{
+   if (!buf)
+      return false;
+   return fifo_initialize_internal(buf, size);
+}
+
+void fifo_free(fifo_buffer_t *buffer)
+{
+   if (!buffer)
+      return;
+
+   free(buffer->buffer);
+   free(buffer);
+}
+
+bool fifo_deinitialize(fifo_buffer_t *buffer)
+{
+   if (!buffer)
+      return false;
+
+   if (buffer->buffer)
+      free(buffer->buffer);
+   buffer->buffer = NULL;
+   buffer->size   = 0;
+   buffer->first  = 0;
+   buffer->end    = 0;
+
+   return true;
+}
+
+fifo_buffer_t *fifo_new(size_t size)
+{
+   fifo_buffer_t *buf = (fifo_buffer_t*)malloc(sizeof(*buf));
+
+   if (!buf)
+      return NULL;
+
+   if (!fifo_initialize_internal(buf, size))
+   {
+      free(buf);
+      return NULL;
+   }
+
+   return buf;
+}
+
+void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size)
+{
+   size_t first_write = size;
+   size_t rest_write  = 0;
+
+   if (buffer->end + size > buffer->size)
+   {
+      first_write = buffer->size - buffer->end;
+      rest_write  = size - first_write;
+   }
+
+   memcpy(buffer->buffer + buffer->end, in_buf, first_write);
+   memcpy(buffer->buffer, (const uint8_t*)in_buf + first_write, rest_write);
+
+   buffer->end = (buffer->end + size) % buffer->size;
+}
+
+void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size)
+{
+   size_t first_read = size;
+   size_t rest_read  = 0;
+
+   if (buffer->first + size > buffer->size)
+   {
+      first_read = buffer->size - buffer->first;
+      rest_read  = size - first_read;
+   }
+
+   memcpy(in_buf, (const uint8_t*)buffer->buffer + buffer->first, first_read);
+   memcpy((uint8_t*)in_buf + first_read, buffer->buffer, rest_read);
+
+   buffer->first = (buffer->first + size) % buffer->size;
+}
diff --git a/deps/libretro-common/queues/generic_queue.c b/deps/libretro-common/queues/generic_queue.c
new file mode 100644 (file)
index 0000000..f8e5c3d
--- /dev/null
@@ -0,0 +1,303 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (generic_queue.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <boolean.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <queues/generic_queue.h>
+
+struct generic_queue_item_t
+{
+   void *value;
+   struct generic_queue_item_t *previous;
+   struct generic_queue_item_t *next;
+};
+
+struct generic_queue
+{
+   struct generic_queue_item_t *first_item;
+   struct generic_queue_item_t *last_item;
+   size_t length;
+};
+
+struct generic_queue_iterator
+{
+   generic_queue_t *queue;
+   struct generic_queue_item_t *item;
+   bool forward;
+};
+
+generic_queue_t *generic_queue_new(void)
+{
+   return (generic_queue_t *)calloc(1, sizeof(generic_queue_t));
+}
+
+void generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value))
+{
+   struct generic_queue_item_t *next_item;
+
+   if (!queue)
+      return;
+
+   while (queue->first_item)
+   {
+      if (free_value)
+         free_value(queue->first_item->value);
+
+      next_item = queue->first_item->next;
+      free(queue->first_item);
+      queue->first_item = next_item;
+   }
+
+   free(queue);
+}
+
+void generic_queue_push(generic_queue_t *queue, void *value)
+{
+   struct generic_queue_item_t *new_item;
+
+   new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t));
+   new_item->value = value;
+   new_item->previous = queue->last_item;
+   new_item->next = NULL;
+
+   queue->last_item = new_item;
+   queue->length++;
+
+   if (!queue->first_item)
+      queue->first_item = new_item;
+   else
+      new_item->previous->next = new_item;
+}
+
+void *generic_queue_pop(generic_queue_t *queue)
+{
+   void *value;
+   struct generic_queue_item_t *item;
+
+   if (!queue || !queue->last_item)
+      return NULL;
+
+   item = queue->last_item;
+   queue->last_item = queue->last_item->previous;
+   queue->length--;
+
+   if (queue->length == 0)
+      queue->first_item = NULL;
+
+   value = item->value;
+   free(item);
+
+   return value;
+}
+
+void *generic_queue_peek(generic_queue_t *queue)
+{
+   if (!queue || !queue->last_item)
+      return NULL;
+
+   return queue->last_item->value;
+}
+
+void *generic_queue_peek_first(generic_queue_t *queue)
+{
+   if (!queue || !queue->first_item)
+      return NULL;
+
+   return queue->first_item->value;
+}
+
+void generic_queue_shift(generic_queue_t *queue, void *value)
+{
+   struct generic_queue_item_t *new_item;
+
+   if (!queue)
+      return;
+
+   new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t));
+   new_item->value = value;
+   new_item->previous = NULL;
+   new_item->next = queue->first_item;
+
+   queue->first_item = new_item;
+   queue->length++;
+
+   if (!queue->last_item)
+      queue->last_item = new_item;
+   else
+      new_item->next->previous = new_item;
+}
+
+void *generic_queue_unshift(generic_queue_t *queue)
+{
+   void *value;
+   struct generic_queue_item_t *item;
+
+   if (!queue || !queue->first_item)
+      return NULL;
+
+   item = queue->first_item;
+   queue->first_item = queue->first_item->next;
+   queue->length--;
+
+   if (queue->length == 0)
+      queue->last_item = NULL;
+
+   value = item->value;
+   free(item);
+
+   return value;
+}
+
+size_t generic_queue_length(generic_queue_t *queue)
+{
+   if (queue)
+      return queue->length;
+
+   return 0;
+}
+
+void *generic_queue_remove(generic_queue_t *queue, void *value)
+{
+   struct generic_queue_item_t *item;
+
+   if (!queue)
+      return NULL;
+
+   for (item = queue->first_item; item; item = item->next)
+   {
+      if (item->value == value)
+      {
+         if (item->previous)
+            item->previous->next = item->next;
+         else
+            queue->first_item = item->next;
+
+         if (item->next)
+            item->next->previous = item->previous;
+         else
+            queue->last_item = item->previous;
+
+         free(item);
+         queue->length--;
+
+         return value;
+      }
+   }
+
+   return NULL;
+}
+
+generic_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward)
+{
+   if (queue && queue->first_item)
+   {
+      generic_queue_iterator_t *iterator;
+
+      iterator = (generic_queue_iterator_t *)malloc(sizeof(generic_queue_iterator_t));
+      iterator->queue = queue;
+      iterator->item = forward ? queue->first_item : queue->last_item;
+      iterator->forward = forward;
+
+      return iterator;
+   }
+
+   return NULL;
+}
+
+generic_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator)
+{
+   if (iterator)
+   {
+      struct generic_queue_item_t *item;
+
+      item = iterator->forward ? iterator->item->next : iterator->item->previous;
+      if (item)
+      {
+         iterator->item = item;
+         return iterator;
+      } else
+      {
+         free(iterator);
+         return NULL;
+      }
+   }
+
+   return NULL;
+}
+
+void *generic_queue_iterator_value(generic_queue_iterator_t *iterator)
+{
+   if (iterator)
+      return iterator->item->value;
+
+   return NULL;
+}
+
+generic_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator)
+{
+   struct generic_queue_item_t *item;
+
+   if (!iterator)
+      return NULL;
+
+   item = iterator->forward ? iterator->queue->first_item : iterator->queue->last_item;
+   while (item)
+   {
+      if (iterator->item == item)
+      {
+         if (iterator->queue->first_item == item)
+            iterator->queue->first_item = item->next;
+         else
+            item->previous->next = item->next;
+
+         if (iterator->queue->last_item == item)
+            iterator->queue->last_item = item->previous;
+         else
+            item->next->previous = item->previous;
+
+         iterator->queue->length--;
+
+         iterator->item = iterator->forward ? item->next : item->previous;
+         free(item);
+         if (iterator->item)
+         {
+            return iterator;
+         } else
+         {
+            free(iterator);
+            return NULL;
+         }
+      }
+
+      item = iterator->forward ? item->next : item->previous;
+   }
+
+   return iterator;
+}
+
+void generic_queue_iterator_free(generic_queue_iterator_t *iterator)
+{
+   if (iterator)
+      free(iterator);
+}
diff --git a/deps/libretro-common/queues/message_queue.c b/deps/libretro-common/queues/message_queue.c
new file mode 100644 (file)
index 0000000..13bf45b
--- /dev/null
@@ -0,0 +1,351 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (message_queue.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <boolean.h>
+#include <queues/message_queue.h>
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+
+static bool msg_queue_initialize_internal(msg_queue_t *queue, size_t size)
+{
+   struct queue_elem **elems = (struct queue_elem**)calloc(size + 1,
+         sizeof(struct queue_elem*));
+
+   if (!elems)
+      return false;
+
+   queue->tmp_msg            = NULL;
+   queue->elems              = elems;
+   queue->ptr                = 1;
+   queue->size               = size + 1;
+
+   return true;
+}
+
+/**
+ * msg_queue_new:
+ * @size              : maximum size of message
+ *
+ * Creates a message queue with maximum size different messages.
+ *
+ * Returns: NULL if allocation error, pointer to a message queue
+ * if successful. Has to be freed manually.
+ **/
+msg_queue_t *msg_queue_new(size_t size)
+{
+   msg_queue_t *queue        = (msg_queue_t*)malloc(sizeof(*queue));
+
+   if (!queue)
+      return NULL;
+
+   if (!msg_queue_initialize_internal(queue, size))
+   {
+      free(queue);
+      return NULL;
+   }
+
+   return queue;
+}
+
+bool msg_queue_initialize(msg_queue_t *queue, size_t size)
+{
+   if (!queue)
+      return false;
+   return msg_queue_initialize_internal(queue, size);
+}
+
+/**
+ * msg_queue_free:
+ * @queue             : pointer to queue object
+ *
+ * Frees message queue..
+ **/
+void msg_queue_free(msg_queue_t *queue)
+{
+   if (!queue)
+      return;
+   msg_queue_clear(queue);
+   free(queue->elems);
+   free(queue);
+}
+
+bool msg_queue_deinitialize(msg_queue_t *queue)
+{
+   if (!queue)
+      return false;
+   msg_queue_clear(queue);
+   free(queue->elems);
+   queue->elems   = NULL;
+   queue->tmp_msg = NULL;
+   queue->ptr     = 0;
+   queue->size    = 0;
+   return true;
+}
+
+/**
+ * msg_queue_push:
+ * @queue             : pointer to queue object
+ * @msg               : message to add to the queue
+ * @prio              : priority level of the message
+ * @duration          : how many times the message can be pulled
+ *                      before it vanishes (E.g. show a message for
+ *                      3 seconds @ 60fps = 180 duration).
+ *
+ * Push a new message onto the queue.
+ **/
+void msg_queue_push(msg_queue_t *queue, const char *msg,
+      unsigned prio, unsigned duration,
+      char *title,
+      enum message_queue_icon icon, enum message_queue_category category)
+{
+   size_t tmp_ptr = 0;
+   struct queue_elem *new_elem = NULL;
+
+   if (!queue || queue->ptr >= queue->size)
+      return;
+
+   new_elem                      = (struct queue_elem*)malloc(
+      sizeof(struct queue_elem));
+   if (!new_elem)
+      return;
+
+   new_elem->duration            = duration;
+   new_elem->prio                = prio;
+   new_elem->msg                 = msg   ? strdup(msg)   : NULL;
+   new_elem->title               = title ? strdup(title) : NULL;
+   new_elem->icon                = icon;
+   new_elem->category            = category;
+
+   queue->elems[queue->ptr]      = new_elem;
+
+   tmp_ptr                       = queue->ptr++;
+
+   while (tmp_ptr > 1)
+   {
+      struct queue_elem *parent  = queue->elems[tmp_ptr >> 1];
+      struct queue_elem *child   = queue->elems[tmp_ptr];
+
+      if (child->prio <= parent->prio)
+         break;
+
+      queue->elems[tmp_ptr >> 1] = child;
+      queue->elems[tmp_ptr]      = parent;
+
+      tmp_ptr >>= 1;
+   }
+}
+
+/**
+ * msg_queue_clear:
+ * @queue             : pointer to queue object
+ *
+ * Clears out everything in the queue.
+ **/
+void msg_queue_clear(msg_queue_t *queue)
+{
+   size_t i;
+
+   if (!queue)
+      return;
+
+   for (i = 1; i < queue->ptr; i++)
+   {
+      if (queue->elems[i])
+      {
+         free(queue->elems[i]->msg);
+         free(queue->elems[i]->title);
+         free(queue->elems[i]);
+         queue->elems[i] = NULL;
+      }
+   }
+   queue->ptr = 1;
+   free(queue->tmp_msg);
+   queue->tmp_msg = NULL;
+}
+
+/**
+ * msg_queue_pull:
+ * @queue             : pointer to queue object
+ *
+ * Pulls highest priority message in queue.
+ *
+ * Returns: NULL if no message in queue, otherwise a string
+ * containing the message.
+ **/
+const char *msg_queue_pull(msg_queue_t *queue)
+{
+   struct queue_elem *front  = NULL, *last = NULL;
+   size_t tmp_ptr = 1;
+
+   (void)tmp_ptr;
+
+   /* Nothing in queue. */
+   if (!queue || queue->ptr == 1)
+      return NULL;
+
+   front = (struct queue_elem*)queue->elems[1];
+   front->duration--;
+   if (front->duration > 0)
+      return front->msg;
+
+   free(queue->tmp_msg);
+   queue->tmp_msg = front->msg;
+   front->msg = NULL;
+
+   last  = (struct queue_elem*)queue->elems[--queue->ptr];
+   queue->elems[1] = last;
+   free(front->title);
+   free(front);
+
+   for (;;)
+   {
+      struct queue_elem *parent = NULL;
+      struct queue_elem *child  = NULL;
+      size_t switch_index       = tmp_ptr;
+      bool left                 = (tmp_ptr * 2 <= queue->ptr)
+         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);
+      bool right                = (tmp_ptr * 2 + 1 <= queue->ptr)
+         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);
+
+      if (!left && !right)
+         break;
+
+      if (left && !right)
+         switch_index <<= 1;
+      else if (right && !left)
+         switch_index += switch_index + 1;
+      else
+      {
+         if (queue->elems[tmp_ptr * 2]
+               >= queue->elems[tmp_ptr * 2 + 1])
+            switch_index <<= 1;
+         else
+            switch_index += switch_index + 1;
+      }
+
+      parent = (struct queue_elem*)queue->elems[tmp_ptr];
+      child  = (struct queue_elem*)queue->elems[switch_index];
+      queue->elems[tmp_ptr]      = child;
+      queue->elems[switch_index] = parent;
+      tmp_ptr                    = switch_index;
+   }
+
+   return queue->tmp_msg;
+}
+
+/**
+ * msg_queue_extract:
+ * @queue             : pointer to queue object
+ * @queue_entry       : pointer to external queue entry struct
+ *
+ * Removes highest priority message from queue, copying
+ * contents into queue_entry struct.
+ *
+ * Returns: false if no messages in queue, otherwise true
+ **/
+bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry)
+{
+   struct queue_elem *front  = NULL, *last = NULL;
+   size_t tmp_ptr = 1;
+
+   /* Ensure arguments are valid and queue is not
+    * empty */
+   if (!queue || queue->ptr == 1 || !queue_entry)
+      return false;
+
+   front = (struct queue_elem*)queue->elems[1];
+   last  = (struct queue_elem*)queue->elems[--queue->ptr];
+   queue->elems[1] = last;
+
+   /* Copy element parameters */
+   queue_entry->duration = front->duration;
+   queue_entry->prio     = front->prio;
+   queue_entry->icon     = front->icon;
+   queue_entry->category = front->category;
+   queue_entry->msg[0]   = '\0';
+   queue_entry->title[0] = '\0';
+
+   if (front->msg)
+      strlcpy(queue_entry->msg, front->msg, sizeof(queue_entry->msg));
+
+   if (front->title)
+      strlcpy(queue_entry->title, front->title, sizeof(queue_entry->title));
+
+   /* Delete element */
+   free(front->msg);
+   free(front->title);
+   free(front);
+
+   for (;;)
+   {
+      struct queue_elem *parent = NULL;
+      struct queue_elem *child  = NULL;
+      size_t switch_index       = tmp_ptr;
+      bool left                 = (tmp_ptr * 2 <= queue->ptr)
+         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);
+      bool right                = (tmp_ptr * 2 + 1 <= queue->ptr)
+         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);
+
+      if (!left && !right)
+         break;
+
+      if (left && !right)
+         switch_index <<= 1;
+      else if (right && !left)
+         switch_index += switch_index + 1;
+      else
+      {
+         if (queue->elems[tmp_ptr * 2]
+               >= queue->elems[tmp_ptr * 2 + 1])
+            switch_index <<= 1;
+         else
+            switch_index += switch_index + 1;
+      }
+
+      parent = (struct queue_elem*)queue->elems[tmp_ptr];
+      child  = (struct queue_elem*)queue->elems[switch_index];
+      queue->elems[tmp_ptr]      = child;
+      queue->elems[switch_index] = parent;
+      tmp_ptr                    = switch_index;
+   }
+
+   return true;
+}
+
+/**
+ * msg_queue_size:
+ * @queue             : pointer to queue object
+ *
+ * Fetches number of messages in queue.
+ *
+ * Returns: Number of messages in queue.
+ **/
+size_t msg_queue_size(msg_queue_t *queue)
+{
+   if (!queue || queue->ptr <= 1)
+      return 0;
+
+   return queue->ptr - 1;
+}
diff --git a/deps/libretro-common/queues/task_queue.c b/deps/libretro-common/queues/task_queue.c
new file mode 100644 (file)
index 0000000..137e4ad
--- /dev/null
@@ -0,0 +1,997 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (task_queue.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <queues/task_queue.h>
+
+#include <features/features_cpu.h>
+
+#ifdef HAVE_THREADS
+#include <rthreads/rthreads.h>
+#endif
+
+typedef struct
+{
+   retro_task_t *front;
+   retro_task_t *back;
+} task_queue_t;
+
+struct retro_task_impl
+{
+   retro_task_queue_msg_t msg_push;
+   void (*push_running)(retro_task_t *);
+   void (*cancel)(void *);
+   void (*reset)(void);
+   void (*wait)(retro_task_condition_fn_t, void *);
+   void (*gather)(void);
+   bool (*find)(retro_task_finder_t, void*);
+   void (*retrieve)(task_retriever_data_t *data);
+   void (*init)(void);
+   void (*deinit)(void);
+};
+
+/* TODO/FIXME - static globals */
+static retro_task_queue_msg_t msg_push_bak  = NULL;
+static task_queue_t tasks_running           = {NULL, NULL};
+static task_queue_t tasks_finished          = {NULL, NULL};
+
+static struct retro_task_impl *impl_current = NULL;
+static bool task_threaded_enable            = false;
+
+#ifdef HAVE_THREADS
+static uintptr_t main_thread_id             = 0;
+static slock_t *running_lock                = NULL;
+static slock_t *finished_lock               = NULL;
+static slock_t *property_lock               = NULL;
+static slock_t *queue_lock                  = NULL;
+static scond_t *worker_cond                 = NULL;
+static sthread_t *worker_thread             = NULL;
+static bool worker_continue                 = true; 
+/* use running_lock when touching it */
+#endif
+
+static void task_queue_msg_push(retro_task_t *task,
+      unsigned prio, unsigned duration,
+      bool flush, const char *fmt, ...)
+{
+   char buf[1024];
+   va_list ap;
+
+   buf[0] = '\0';
+
+   va_start(ap, fmt);
+   vsnprintf(buf, sizeof(buf), fmt, ap);
+   va_end(ap);
+
+   if (impl_current->msg_push)
+      impl_current->msg_push(task, buf, prio, duration, flush);
+}
+
+static void task_queue_push_progress(retro_task_t *task)
+{
+#ifdef HAVE_THREADS
+   /* msg_push callback interacts directly with the task properties (particularly title).
+    * make sure another thread doesn't modify them while rendering
+    */
+   slock_lock(property_lock);
+#endif
+
+   if (task->title && !task->mute)
+   {
+      if (task->finished)
+      {
+         if (task->error)
+            task_queue_msg_push(task, 1, 60, true, "%s: %s",
+               "Task failed", task->title);
+         else
+            task_queue_msg_push(task, 1, 60, false, "100%%: %s", task->title);
+      }
+      else
+      {
+         if (task->progress >= 0 && task->progress <= 100)
+            task_queue_msg_push(task, 1, 60, true, "%i%%: %s",
+                  task->progress, task->title);
+         else
+            task_queue_msg_push(task, 1, 60, false, "%s...", task->title);
+      }
+
+      if (task->progress_cb)
+         task->progress_cb(task);
+   }
+
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+}
+
+static void task_queue_put(task_queue_t *queue, retro_task_t *task)
+{
+   task->next                   = NULL;
+
+   if (queue->front)
+   {
+      /* Make sure to insert in order - the queue is 
+       * sorted by 'when' so items that aren't scheduled
+       * to run immediately are at the back of the queue. 
+       * Items with the same 'when' are inserted after
+       * all the other items with the same 'when'. 
+       * This primarily affects items with a 'when' of 0.
+       */
+      if (queue->back)
+      {
+         if (queue->back->when > task->when)
+         {
+            retro_task_t** prev = &queue->front;
+            while (*prev && (*prev)->when <= task->when)
+               prev             = &((*prev)->next);
+
+            task->next          = *prev;
+            *prev               = task;
+            return;
+         }
+
+         queue->back->next      = task;
+      }
+   }
+   else
+      queue->front              = task;
+
+   queue->back                  = task;
+}
+
+static retro_task_t *task_queue_get(task_queue_t *queue)
+{
+   retro_task_t *task = queue->front;
+
+   if (task)
+   {
+      queue->front = task->next;
+      task->next   = NULL;
+   }
+
+   return task;
+}
+
+static void retro_task_internal_gather(void)
+{
+   retro_task_t *task = NULL;
+   while ((task = task_queue_get(&tasks_finished)))
+   {
+      task_queue_push_progress(task);
+
+      if (task->callback)
+         task->callback(task, task->task_data, task->user_data, task->error);
+
+      if (task->cleanup)
+          task->cleanup(task);
+
+      if (task->error)
+         free(task->error);
+
+      if (task->title)
+         free(task->title);
+
+      free(task);
+   }
+}
+
+static void retro_task_regular_push_running(retro_task_t *task)
+{
+   task_queue_put(&tasks_running, task);
+}
+
+static void retro_task_regular_cancel(void *task)
+{
+   retro_task_t *t = (retro_task_t*)task;
+   t->cancelled    = true;
+}
+
+static void retro_task_regular_gather(void)
+{
+   retro_task_t *task  = NULL;
+   retro_task_t *queue = NULL;
+   retro_task_t *next  = NULL;
+
+   while ((task = task_queue_get(&tasks_running)))
+   {
+      task->next = queue;
+      queue = task;
+   }
+
+   for (task = queue; task; task = next)
+   {
+      next = task->next;
+
+      if (!task->when || task->when < cpu_features_get_time_usec())
+      {
+         task->handler(task);
+
+         task_queue_push_progress(task);
+      }
+
+      if (task->finished)
+         task_queue_put(&tasks_finished, task);
+      else
+         retro_task_regular_push_running(task);
+   }
+
+   retro_task_internal_gather();
+}
+
+static void retro_task_regular_wait(retro_task_condition_fn_t cond, void* data)
+{
+   while ((tasks_running.front && !tasks_running.front->when) && (!cond || cond(data)))
+      retro_task_regular_gather();
+}
+
+static void retro_task_regular_reset(void)
+{
+   retro_task_t *task = tasks_running.front;
+
+   for (; task; task = task->next)
+      task->cancelled = true;
+}
+
+static void retro_task_regular_init(void) { }
+static void retro_task_regular_deinit(void) { }
+
+static bool retro_task_regular_find(retro_task_finder_t func, void *user_data)
+{
+   retro_task_t *task = tasks_running.front;
+
+   for (; task; task = task->next)
+   {
+      if (func(task, user_data))
+         return true;
+   }
+
+   return false;
+}
+
+static void retro_task_regular_retrieve(task_retriever_data_t *data)
+{
+   retro_task_t *task          = NULL;
+   task_retriever_info_t *tail = NULL;
+
+   /* Parse all running tasks and handle matching handlers */
+   for (task = tasks_running.front; task != NULL; task = task->next)
+   {
+      task_retriever_info_t *info = NULL;
+      if (task->handler != data->handler)
+         continue;
+
+      /* Create new link */
+      info       = (task_retriever_info_t*)
+         malloc(sizeof(task_retriever_info_t));
+      info->data = malloc(data->element_size);
+      info->next = NULL;
+
+      /* Call retriever function and fill info-specific data */
+      if (!data->func(task, info->data))
+      {
+         free(info->data);
+         free(info);
+         continue;
+      }
+
+      /* Add link to list */
+      if (data->list)
+      {
+         if (tail)
+         {
+            tail->next = info;
+            tail       = tail->next;
+         }
+         else
+            tail       = info;
+      }
+      else
+      {
+         data->list    = info;
+         tail          = data->list;
+      }
+   }
+}
+
+static struct retro_task_impl impl_regular = {
+   NULL,
+   retro_task_regular_push_running,
+   retro_task_regular_cancel,
+   retro_task_regular_reset,
+   retro_task_regular_wait,
+   retro_task_regular_gather,
+   retro_task_regular_find,
+   retro_task_regular_retrieve,
+   retro_task_regular_init,
+   retro_task_regular_deinit
+};
+
+#ifdef HAVE_THREADS
+
+/* 'queue_lock' must be held for the duration of this function */
+static void task_queue_remove(task_queue_t *queue, retro_task_t *task)
+{
+   retro_task_t     *t = NULL;
+   retro_task_t *front = queue->front;
+
+   /* Remove first element if needed */
+   if (task == front)
+   {
+      queue->front     = task->next;
+      if (queue->back == task) /* if only element, also update back */
+         queue->back   = NULL;
+      task->next       = NULL;
+      return;
+   }
+
+   /* Parse queue */
+   t = front;
+
+   while (t && t->next)
+   {
+      /* Remove task and update queue */
+      if (t->next == task)
+      {
+         t->next    = task->next;
+         task->next = NULL;
+
+         /* When removing the tail of the queue, update the tail pointer */
+         if (queue->back == task)
+         {
+            if (queue->back == task)
+               queue->back = t;
+         }
+         break;
+      }
+
+      /* Update iterator */
+      t = t->next;
+   }
+}
+
+static void retro_task_threaded_push_running(retro_task_t *task)
+{
+   slock_lock(running_lock);
+   slock_lock(queue_lock);
+   task_queue_put(&tasks_running, task);
+   scond_signal(worker_cond);
+   slock_unlock(queue_lock);
+   slock_unlock(running_lock);
+}
+
+static void retro_task_threaded_cancel(void *task)
+{
+   retro_task_t *t;
+
+   slock_lock(running_lock);
+
+   for (t = tasks_running.front; t; t = t->next)
+   {
+      if (t == task)
+      {
+        t->cancelled = true;
+        break;
+      }
+   }
+
+   slock_unlock(running_lock);
+}
+
+static void retro_task_threaded_gather(void)
+{
+   retro_task_t *task = NULL;
+
+   slock_lock(running_lock);
+   for (task = tasks_running.front; task; task = task->next)
+      task_queue_push_progress(task);
+   slock_unlock(running_lock);
+
+   slock_lock(finished_lock);
+   retro_task_internal_gather();
+   slock_unlock(finished_lock);
+}
+
+static void retro_task_threaded_wait(retro_task_condition_fn_t cond, void* data)
+{
+   bool wait = false;
+
+   do
+   {
+      retro_task_threaded_gather();
+
+      slock_lock(running_lock);
+      wait = (tasks_running.front && !tasks_running.front->when);
+      slock_unlock(running_lock);
+
+      if (!wait)
+      {
+         slock_lock(finished_lock);
+         wait = (tasks_finished.front && !tasks_finished.front->when);
+         slock_unlock(finished_lock);
+      }
+   } while (wait && (!cond || cond(data)));
+}
+
+static void retro_task_threaded_reset(void)
+{
+   retro_task_t *task = NULL;
+
+   slock_lock(running_lock);
+   for (task = tasks_running.front; task; task = task->next)
+      task->cancelled = true;
+   slock_unlock(running_lock);
+}
+
+static bool retro_task_threaded_find(
+      retro_task_finder_t func, void *user_data)
+{
+   retro_task_t *task = NULL;
+   bool        result = false;
+
+   slock_lock(running_lock);
+   for (task = tasks_running.front; task; task = task->next)
+   {
+      if (func(task, user_data))
+      {
+         result = true;
+         break;
+      }
+   }
+   slock_unlock(running_lock);
+
+   return result;
+}
+
+static void retro_task_threaded_retrieve(task_retriever_data_t *data)
+{
+   /* Protect access to running tasks */
+   slock_lock(running_lock);
+
+   /* Call regular retrieve function */
+   retro_task_regular_retrieve(data);
+
+   /* Release access to running tasks */
+   slock_unlock(running_lock);
+}
+
+static void threaded_worker(void *userdata)
+{
+   (void)userdata;
+
+   for (;;)
+   {
+      retro_task_t *task  = NULL;
+      bool       finished = false;
+
+      if (!worker_continue)
+         break; /* should we keep running until all tasks finished? */
+
+      slock_lock(running_lock);
+
+      /* Get first task to run */
+      if (!(task = tasks_running.front))
+      {
+         scond_wait(worker_cond, running_lock);
+         slock_unlock(running_lock);
+         continue;
+      }
+
+      if (task->when)
+      {
+         retro_time_t now   = cpu_features_get_time_usec();
+         retro_time_t delay = task->when - now - 500; /* allow half a millisecond for context switching */
+         if (delay > 0)
+         {
+            scond_wait_timeout(worker_cond, running_lock, delay);
+            slock_unlock(running_lock);
+            continue;
+         }
+      }
+
+      slock_unlock(running_lock);
+
+      task->handler(task);
+
+      slock_lock(property_lock);
+      finished = task->finished;
+      slock_unlock(property_lock);
+
+      /* Update queue */
+      if (!finished)
+      {
+         /* Move the task to the back of the queue */
+         /* mimics retro_task_threaded_push_running, 
+          * but also includes a task_queue_remove */
+         slock_lock(running_lock);
+         slock_lock(queue_lock);
+
+         /* do nothing if only item in queue */
+         if (task->next) 
+         {
+            task_queue_remove(&tasks_running, task);
+            task_queue_put(&tasks_running, task);
+            scond_signal(worker_cond);
+         }
+         slock_unlock(queue_lock);
+         slock_unlock(running_lock);
+      }
+      else
+      {
+         /* Remove task from running queue */
+         slock_lock(running_lock);
+         slock_lock(queue_lock);
+         task_queue_remove(&tasks_running, task);
+         slock_unlock(queue_lock);
+         slock_unlock(running_lock);
+
+         /* Add task to finished queue */
+         slock_lock(finished_lock);
+         task_queue_put(&tasks_finished, task);
+         slock_unlock(finished_lock);
+      }
+   }
+}
+
+static void retro_task_threaded_init(void)
+{
+   running_lock    = slock_new();
+   finished_lock   = slock_new();
+   property_lock   = slock_new();
+   queue_lock      = slock_new();
+   worker_cond     = scond_new();
+
+   slock_lock(running_lock);
+   worker_continue = true;
+   slock_unlock(running_lock);
+
+   worker_thread   = sthread_create(threaded_worker, NULL);
+}
+
+static void retro_task_threaded_deinit(void)
+{
+   slock_lock(running_lock);
+   worker_continue = false;
+   scond_signal(worker_cond);
+   slock_unlock(running_lock);
+
+   sthread_join(worker_thread);
+
+   scond_free(worker_cond);
+   slock_free(running_lock);
+   slock_free(finished_lock);
+   slock_free(property_lock);
+   slock_free(queue_lock);
+
+   worker_thread   = NULL;
+   worker_cond     = NULL;
+   running_lock    = NULL;
+   finished_lock   = NULL;
+   property_lock   = NULL;
+   queue_lock      = NULL;
+}
+
+static struct retro_task_impl impl_threaded = {
+   NULL,
+   retro_task_threaded_push_running,
+   retro_task_threaded_cancel,
+   retro_task_threaded_reset,
+   retro_task_threaded_wait,
+   retro_task_threaded_gather,
+   retro_task_threaded_find,
+   retro_task_threaded_retrieve,
+   retro_task_threaded_init,
+   retro_task_threaded_deinit
+};
+#endif
+
+/* Deinitializes the task system.
+ * This deinitializes the task system.
+ * The tasks that are running at
+ * the moment will stay on hold */
+void task_queue_deinit(void)
+{
+   if (impl_current)
+      impl_current->deinit();
+   impl_current = NULL;
+}
+
+void task_queue_init(bool threaded, retro_task_queue_msg_t msg_push)
+{
+   impl_current   = &impl_regular;
+#ifdef HAVE_THREADS
+   main_thread_id = sthread_get_current_thread_id();
+   if (threaded)
+   {
+      task_threaded_enable = true;
+      impl_current         = &impl_threaded;
+   }
+#endif
+
+   msg_push_bak            = msg_push;
+
+   impl_current->msg_push  = msg_push;
+   impl_current->init();
+}
+
+void task_queue_set_threaded(void)
+{
+   task_threaded_enable = true;
+}
+
+void task_queue_unset_threaded(void)
+{
+   task_threaded_enable = false;
+}
+
+bool task_queue_is_threaded(void)
+{
+   return task_threaded_enable;
+}
+
+bool task_queue_find(task_finder_data_t *find_data)
+{
+   return impl_current->find(find_data->func, find_data->userdata);
+}
+
+void task_queue_retrieve(task_retriever_data_t *data)
+{
+   impl_current->retrieve(data);
+}
+
+void task_queue_check(void)
+{
+#ifdef HAVE_THREADS
+   bool current_threaded = (impl_current == &impl_threaded);
+   bool want_threaded    = task_threaded_enable;
+
+   if (want_threaded != current_threaded)
+      task_queue_deinit();
+
+   if (!impl_current)
+      task_queue_init(want_threaded, msg_push_bak);
+#endif
+
+   impl_current->gather();
+}
+
+bool task_queue_push(retro_task_t *task)
+{
+   /* Ignore this task if a related one is already running */
+   if (task->type == TASK_TYPE_BLOCKING)
+   {
+      retro_task_t *running = NULL;
+      bool            found = false;
+
+#ifdef HAVE_THREADS
+      slock_lock(queue_lock);
+#endif
+      running = tasks_running.front;
+
+      for (; running; running = running->next)
+      {
+         if (running->type == TASK_TYPE_BLOCKING)
+         {
+            found = true;
+            break;
+         }
+      }
+
+#ifdef HAVE_THREADS
+      slock_unlock(queue_lock);
+#endif
+
+      /* skip this task, user must try again later */
+      if (found)
+         return false;
+   }
+
+   /* The lack of NULL checks in the following functions
+    * is proposital to ensure correct control flow by the users. */
+   impl_current->push_running(task);
+
+   return true;
+}
+
+void task_queue_wait(retro_task_condition_fn_t cond, void* data)
+{
+   impl_current->wait(cond, data);
+}
+
+void task_queue_reset(void)
+{
+   impl_current->reset();
+}
+
+/**
+ * Signals a task to end without waiting for
+ * it to complete. */
+void task_queue_cancel_task(void *task)
+{
+   impl_current->cancel(task);
+}
+
+void *task_queue_retriever_info_next(task_retriever_info_t **link)
+{
+   void *data = NULL;
+
+   /* Grab data and move to next link */
+   if (*link)
+   {
+      data  = (*link)->data;
+      *link = (*link)->next;
+   }
+
+   return data;
+}
+
+void task_queue_retriever_info_free(task_retriever_info_t *list)
+{
+   task_retriever_info_t *info;
+
+   /* Free links including retriever-specific data */
+   while (list)
+   {
+      info = list->next;
+      free(list->data);
+      free(list);
+      list = info;
+   }
+}
+
+bool task_is_on_main_thread(void)
+{
+#ifdef HAVE_THREADS
+   return sthread_get_current_thread_id() == main_thread_id;
+#else
+   return true;
+#endif
+}
+
+void task_set_finished(retro_task_t *task, bool finished)
+{
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   task->finished = finished;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+}
+
+void task_set_mute(retro_task_t *task, bool mute)
+{
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   task->mute = mute;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+}
+
+void task_set_error(retro_task_t *task, char *error)
+{
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   task->error = error;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+}
+
+void task_set_progress(retro_task_t *task, int8_t progress)
+{
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   task->progress = progress;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+}
+
+void task_set_title(retro_task_t *task, char *title)
+{
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   task->title = title;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+}
+
+void task_set_data(retro_task_t *task, void *data)
+{
+#ifdef HAVE_THREADS
+   slock_lock(running_lock);
+#endif
+   task->task_data = data;
+#ifdef HAVE_THREADS
+   slock_unlock(running_lock);
+#endif
+}
+
+void task_set_cancelled(retro_task_t *task, bool cancelled)
+{
+#ifdef HAVE_THREADS
+   slock_lock(running_lock);
+#endif
+   task->cancelled = cancelled;
+#ifdef HAVE_THREADS
+   slock_unlock(running_lock);
+#endif
+}
+
+void task_free_title(retro_task_t *task)
+{
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   if (task->title)
+      free(task->title);
+   task->title = NULL;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+}
+
+void* task_get_data(retro_task_t *task)
+{
+   void *data = NULL;
+
+#ifdef HAVE_THREADS
+   slock_lock(running_lock);
+#endif
+   data = task->task_data;
+#ifdef HAVE_THREADS
+   slock_unlock(running_lock);
+#endif
+
+   return data;
+}
+
+bool task_get_cancelled(retro_task_t *task)
+{
+   bool cancelled = false;
+
+#ifdef HAVE_THREADS
+   slock_lock(running_lock);
+#endif
+   cancelled = task->cancelled;
+#ifdef HAVE_THREADS
+   slock_unlock(running_lock);
+#endif
+
+   return cancelled;
+}
+
+bool task_get_finished(retro_task_t *task)
+{
+   bool finished = false;
+
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   finished = task->finished;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+
+   return finished;
+}
+
+bool task_get_mute(retro_task_t *task)
+{
+   bool mute = false;
+
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   mute = task->mute;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+
+   return mute;
+}
+
+char* task_get_error(retro_task_t *task)
+{
+   char *error = NULL;
+
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   error = task->error;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+
+   return error;
+}
+
+int8_t task_get_progress(retro_task_t *task)
+{
+   int8_t progress = 0;
+
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   progress = task->progress;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+
+   return progress;
+}
+
+char* task_get_title(retro_task_t *task)
+{
+   char *title = NULL;
+
+#ifdef HAVE_THREADS
+   slock_lock(property_lock);
+#endif
+   title = task->title;
+#ifdef HAVE_THREADS
+   slock_unlock(property_lock);
+#endif
+
+   return title;
+}
+
+retro_task_t *task_init(void)
+{
+   /* TODO/FIXME - static local global */
+   static uint32_t task_count = 0;
+   retro_task_t *task         = (retro_task_t*)malloc(sizeof(*task));
+
+   if (!task)
+      return NULL;
+
+   task->handler           = NULL;
+   task->callback          = NULL;
+   task->cleanup           = NULL;
+   task->finished          = false;
+   task->cancelled         = false;
+   task->mute              = false;
+   task->task_data         = NULL;
+   task->user_data         = NULL;
+   task->state             = NULL;
+   task->error             = NULL;
+   task->progress          = 0;
+   task->progress_cb       = NULL;
+   task->title             = NULL;
+   task->type              = TASK_TYPE_NONE;
+   task->ident             = task_count++;
+   task->frontend_userdata = NULL;
+   task->alternative_look  = false;
+   task->next              = NULL;
+   task->when              = 0;
+
+   return task;
+}
diff --git a/deps/libretro-common/rthreads/ctr_pthread.h b/deps/libretro-common/rthreads/ctr_pthread.h
new file mode 100644 (file)
index 0000000..5582af1
--- /dev/null
@@ -0,0 +1,326 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (gx_pthread.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _CTR_PTHREAD_WRAP_CTR_
+#define _CTR_PTHREAD_WRAP_CTR_
+
+#include <3ds/thread.h>
+#include <3ds/synchronization.h>
+#include <3ds/svc.h>
+#include <time.h>
+#include <errno.h>
+#include <retro_inline.h>
+
+#define STACKSIZE (32 * 1024)
+
+#ifndef PTHREAD_SCOPE_PROCESS
+/* An earlier version of devkitARM does not define the pthread types. Can remove in r54+. */
+
+typedef Thread     pthread_t;
+typedef LightLock  pthread_mutex_t;
+typedef void*      pthread_mutexattr_t;
+typedef int        pthread_attr_t;
+typedef uint32_t   pthread_cond_t;
+typedef int        pthread_condattr_t;
+#endif
+
+#ifndef USE_CTRULIB_2
+/* Backported CondVar API from libctru 2.0, and under its license:
+   https://github.com/devkitPro/libctru
+   Slightly modified for compatibility with older libctru. */
+
+typedef s32 CondVar;
+
+static INLINE Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value)
+{
+   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, 0);
+}
+
+static INLINE Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns)
+{
+   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, timeout_ns);
+}
+
+static INLINE void __dmb(void)
+{
+       __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
+}
+
+static INLINE void CondVar_BeginWait(CondVar* cv, LightLock* lock)
+{
+       s32 val;
+       do
+               val = __ldrex(cv) - 1;
+       while (__strex(cv, val));
+       LightLock_Unlock(lock);
+}
+
+static INLINE bool CondVar_EndWait(CondVar* cv, s32 num_threads)
+{
+       bool hasWaiters;
+       s32 val;
+
+       do {
+               val = __ldrex(cv);
+               hasWaiters = val < 0;
+               if (hasWaiters)
+               {
+                       if (num_threads < 0)
+                               val = 0;
+                       else if (val <= -num_threads)
+                               val += num_threads;
+                       else
+                               val = 0;
+               }
+       } while (__strex(cv, val));
+
+       return hasWaiters;
+}
+
+static INLINE void CondVar_Init(CondVar* cv)
+{
+       *cv = 0;
+}
+
+static INLINE void CondVar_Wait(CondVar* cv, LightLock* lock)
+{
+       CondVar_BeginWait(cv, lock);
+       syncArbitrateAddress(cv, ARBITRATION_WAIT_IF_LESS_THAN, 0);
+       LightLock_Lock(lock);
+}
+
+static INLINE int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns)
+{
+       CondVar_BeginWait(cv, lock);
+
+       bool timedOut = false;
+       Result rc = syncArbitrateAddressWithTimeout(cv, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, timeout_ns);
+       if (R_DESCRIPTION(rc) == RD_TIMEOUT)
+       {
+               timedOut = CondVar_EndWait(cv, 1);
+               __dmb();
+       }
+
+       LightLock_Lock(lock);
+       return timedOut;
+}
+
+static INLINE void CondVar_WakeUp(CondVar* cv, s32 num_threads)
+{
+       __dmb();
+       if (CondVar_EndWait(cv, num_threads))
+               syncArbitrateAddress(cv, ARBITRATION_SIGNAL, num_threads);
+       else
+               __dmb();
+}
+
+static INLINE void CondVar_Signal(CondVar* cv)
+{
+       CondVar_WakeUp(cv, 1);
+}
+
+static INLINE void CondVar_Broadcast(CondVar* cv)
+{
+       CondVar_WakeUp(cv, ARBITRATION_SIGNAL_ALL);
+}
+/* End libctru 2.0 backport */
+#endif
+
+/* libctru threads return void but pthreads return void pointer */
+static bool mutex_inited = false;
+static LightLock safe_double_thread_launch;
+static void *(*start_routine_jump)(void*);
+
+static void ctr_thread_launcher(void* data)
+{
+       void *(*start_routine_jump_safe)(void*) = start_routine_jump;
+       LightLock_Unlock(&safe_double_thread_launch);
+       start_routine_jump_safe(data);
+}
+
+static INLINE int pthread_create(pthread_t *thread,
+      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
+{
+   s32 prio = 0;
+   Thread new_ctr_thread;
+   int procnum = -2; // use default cpu
+   bool isNew3DS;
+
+   APT_CheckNew3DS(&isNew3DS);
+
+   if (isNew3DS)
+      procnum = 2;
+
+   if (!mutex_inited)
+   {
+      LightLock_Init(&safe_double_thread_launch);
+      mutex_inited = true;
+   }
+
+   /*Must wait if attempting to launch 2 threads at once to prevent corruption of function pointer*/
+   while (LightLock_TryLock(&safe_double_thread_launch) != 0);
+
+   svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
+
+   start_routine_jump = start_routine;
+   new_ctr_thread     = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, procnum, false);
+
+   if (!new_ctr_thread)
+   {
+      LightLock_Unlock(&safe_double_thread_launch);
+      return EAGAIN;
+   }
+
+   *thread = (pthread_t)new_ctr_thread;
+   return 0;
+}
+
+static INLINE pthread_t pthread_self(void)
+{
+   return (pthread_t)threadGetCurrent();
+}
+
+static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
+      const pthread_mutexattr_t *attr)
+{
+   LightLock_Init((LightLock *)mutex);
+   return 0;
+}
+
+static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+   /*Nothing to destroy*/
+   return 0;
+}
+
+static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+   LightLock_Lock((LightLock *)mutex);
+   return 0;
+}
+
+static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+   LightLock_Unlock((LightLock *)mutex);
+   return 0;
+}
+
+static INLINE void pthread_exit(void *retval)
+{
+   /*Yes the pointer to int cast is not ideal*/
+   /*threadExit((int)retval);*/
+   (void)retval;
+
+   threadExit(0);
+}
+
+static INLINE int pthread_detach(pthread_t thread)
+{
+   threadDetach((Thread)thread);
+   return 0;
+}
+
+static INLINE int pthread_join(pthread_t thread, void **retval)
+{
+   /*retval is ignored*/
+   if (threadJoin((Thread)thread, INT64_MAX))
+      return -1;
+
+   threadFree((Thread)thread);
+
+   return 0;
+}
+
+static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+   return LightLock_TryLock((LightLock *)mutex);
+}
+
+static INLINE int pthread_cond_wait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex)
+{
+   CondVar_Wait((CondVar *)cond, (LightLock *)mutex);
+   return 0;
+}
+
+static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+   /* Missing clock_gettime*/
+   struct timespec now;
+   struct timeval tm;
+   int retval = 0;
+
+   do
+   {
+      s64 timeout;
+      gettimeofday(&tm, NULL);
+      now.tv_sec  = tm.tv_sec;
+      now.tv_nsec = tm.tv_usec * 1000;
+
+      if ((timeout = (abstime->tv_sec - now.tv_sec) * 1000000000 +
+(abstime->tv_nsec - now.tv_nsec)) < 0)
+      {
+         retval = ETIMEDOUT;
+         break;
+      }
+
+      if (!CondVar_WaitTimeout((CondVar *)cond, (LightLock *)mutex, timeout))
+         break;
+   } while (1);
+
+   return retval;
+}
+
+static INLINE int pthread_cond_init(pthread_cond_t *cond,
+      const pthread_condattr_t *attr)
+{
+   CondVar_Init((CondVar *)cond);
+   return 0;
+}
+
+static INLINE int pthread_cond_signal(pthread_cond_t *cond)
+{
+   CondVar_Signal((CondVar *)cond);
+   return 0;
+}
+
+static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+   CondVar_Broadcast((CondVar *)cond);
+   return 0;
+}
+
+static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
+{
+   /*Nothing to destroy*/
+   return 0;
+}
+
+static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
+{
+       if (threadGetHandle((Thread)t1) == threadGetHandle((Thread)t2))
+               return 1;
+       return 0;
+}
+
+#endif
diff --git a/deps/libretro-common/rthreads/gx_pthread.h b/deps/libretro-common/rthreads/gx_pthread.h
new file mode 100644 (file)
index 0000000..da6efb8
--- /dev/null
@@ -0,0 +1,186 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (gx_pthread.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _GX_PTHREAD_WRAP_GX_
+#define _GX_PTHREAD_WRAP_GX_
+
+#include <ogcsys.h>
+#include <gccore.h>
+#include <ogc/cond.h>
+#include <retro_inline.h>
+
+#ifndef OSThread
+#define OSThread lwp_t
+#endif
+
+#ifndef OSCond
+#define OSCond lwpq_t
+#endif
+
+#ifndef OSThreadQueue
+#define OSThreadQueue lwpq_t
+#endif
+
+#ifndef OSInitMutex
+#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
+#endif
+
+#ifndef OSLockMutex
+#define OSLockMutex(mutex) LWP_MutexLock(mutex)
+#endif
+
+#ifndef OSUnlockMutex
+#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
+#endif
+
+#ifndef OSTryLockMutex
+#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)
+#endif
+
+#ifndef OSInitCond
+#define OSInitCond(cond) LWP_CondInit(cond)
+#endif
+
+#ifndef OSWaitCond
+#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)
+#endif
+
+#ifndef OSInitThreadQueue
+#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
+#endif
+
+#ifndef OSSleepThread
+#define OSSleepThread(queue) LWP_ThreadSleep(queue)
+#endif
+
+#ifndef OSJoinThread
+#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)
+#endif
+
+#ifndef OSCreateThread
+#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)
+#endif
+
+#define STACKSIZE (8 * 1024)
+
+typedef OSThread pthread_t;
+typedef mutex_t pthread_mutex_t;
+typedef OSCond pthread_cond_t;
+
+#if defined(GX_PTHREAD_LEGACY)
+typedef void* pthread_mutexattr_t;
+typedef int pthread_attr_t;
+typedef OSCond pthread_condattr_t;
+#endif
+
+static INLINE int pthread_create(pthread_t *thread,
+      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
+{
+   *thread = 0;
+   return OSCreateThread(thread, start_routine, 0 /* unused */, arg,
+         0, STACKSIZE, 64, 0 /* unused */);
+}
+
+static INLINE pthread_t pthread_self(void)
+{
+   /* zero 20-mar-2016: untested */
+   return LWP_GetSelf();
+}
+
+static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
+      const pthread_mutexattr_t *attr)
+{
+   return OSInitMutex(mutex);
+}
+
+static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+   return LWP_MutexDestroy(*mutex);
+}
+
+static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+   return OSLockMutex(*mutex);
+}
+
+static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+   return OSUnlockMutex(*mutex);
+}
+
+static INLINE void pthread_exit(void *retval)
+{
+   /* FIXME: No LWP equivalent for this? */
+   (void)retval;
+}
+
+static INLINE int pthread_detach(pthread_t thread)
+{
+   /* FIXME: pthread_detach equivalent missing? */
+   (void)thread;
+   return 0;
+}
+
+static INLINE int pthread_join(pthread_t thread, void **retval)
+{
+   return OSJoinThread(thread, retval);
+}
+
+static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+   return OSTryLockMutex(*mutex);
+}
+
+static INLINE int pthread_cond_wait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex)
+{
+   return OSWaitCond(*cond, *mutex);
+}
+
+static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+   return LWP_CondTimedWait(*cond, *mutex, abstime);
+}
+
+static INLINE int pthread_cond_init(pthread_cond_t *cond,
+      const pthread_condattr_t *attr)
+{
+   return OSInitCond(cond);
+}
+
+static INLINE int pthread_cond_signal(pthread_cond_t *cond)
+{
+   return LWP_CondSignal(*cond);
+}
+
+static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+   return LWP_CondBroadcast(*cond);
+}
+
+static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
+{
+   return LWP_CondDestroy(*cond);
+}
+
+#endif
diff --git a/deps/libretro-common/rthreads/psp_pthread.h b/deps/libretro-common/rthreads/psp_pthread.h
new file mode 100644 (file)
index 0000000..f320969
--- /dev/null
@@ -0,0 +1,305 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (psp_pthread.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* FIXME: unfinished on PSP, mutexes and condition variables basically a stub. */
+#ifndef _PSP_PTHREAD_WRAP__
+#define _PSP_PTHREAD_WRAP__
+
+#ifdef VITA
+#include <psp2/kernel/threadmgr.h>
+#include <sys/time.h>
+#else
+#include <pspkernel.h>
+#include <pspthreadman.h>
+#include <pspthreadman_kernel.h>
+#endif
+#include <stdio.h>
+#include <retro_inline.h>
+
+#define STACKSIZE (8 * 1024)
+
+typedef SceUID pthread_t;
+typedef SceUID pthread_mutex_t;
+typedef void* pthread_mutexattr_t;
+typedef int pthread_attr_t;
+
+typedef struct
+{
+       SceUID mutex;
+       SceUID sema;
+       int waiting;
+} pthread_cond_t;
+
+typedef SceUID pthread_condattr_t;
+
+/* Use pointer values to create unique names for threads/mutexes */
+char name_buffer[256];
+
+typedef void* (*sthreadEntry)(void *argp);
+
+typedef struct
+{
+   void* arg;
+   sthreadEntry start_routine;
+} sthread_args_struct;
+
+static int psp_thread_wrap(SceSize args, void *argp)
+{
+   sthread_args_struct* sthread_args = (sthread_args_struct*)argp;
+
+   return (int)sthread_args->start_routine(sthread_args->arg);
+}
+
+static INLINE int pthread_create(pthread_t *thread,
+      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
+{
+   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) thread);
+
+#ifdef VITA
+   *thread = sceKernelCreateThread(name_buffer, psp_thread_wrap,
+         0x10000100, 0x10000, 0, 0, NULL);
+#else
+   *thread = sceKernelCreateThread(name_buffer,
+         psp_thread_wrap, 0x20, STACKSIZE, 0, NULL);
+#endif
+
+   sthread_args_struct sthread_args;
+   sthread_args.arg = arg;
+   sthread_args.start_routine = start_routine;
+
+   return sceKernelStartThread(*thread, sizeof(sthread_args), &sthread_args);
+}
+
+static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
+      const pthread_mutexattr_t *attr)
+{
+   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) mutex);
+
+#ifdef VITA
+   *mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);
+        if (*mutex<0)
+                       return *mutex;
+        return 0;
+#else
+   return *mutex = sceKernelCreateSema(name_buffer, 0, 1, 1, NULL);
+#endif
+}
+
+static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+#ifdef VITA
+   return sceKernelDeleteMutex(*mutex);
+#else
+   return sceKernelDeleteSema(*mutex);
+#endif
+}
+
+static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+#ifdef VITA
+        int ret = sceKernelLockMutex(*mutex, 1, 0);
+        return ret;
+
+#else
+   /* FIXME: stub */
+   return 1;
+#endif
+}
+
+static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+#ifdef VITA
+       int ret = sceKernelUnlockMutex(*mutex, 1);
+       return ret;
+#else
+   /* FIXME: stub */
+   return 1;
+#endif
+}
+
+static INLINE int pthread_join(pthread_t thread, void **retval)
+{
+#ifdef VITA
+   int res = sceKernelWaitThreadEnd(thread, 0, 0);
+   if (res < 0)
+      return res;
+   return sceKernelDeleteThread(thread);
+#else
+   SceUInt timeout = (SceUInt)-1;
+   sceKernelWaitThreadEnd(thread, &timeout);
+   exit_status = sceKernelGetThreadExitStatus(thread);
+   sceKernelDeleteThread(thread);
+   return exit_status;
+#endif
+}
+
+static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+#ifdef VITA
+   return sceKernelTryLockMutex(*mutex, 1 /* not sure about this last param */);
+#else
+   /* FIXME: stub */
+   return 1;
+#endif
+}
+
+static INLINE int pthread_cond_wait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex)
+{
+#ifdef VITA
+   int ret = pthread_mutex_lock(&cond->mutex);
+   if (ret < 0)
+      return ret;
+   ++cond->waiting;
+   pthread_mutex_unlock(mutex);
+   pthread_mutex_unlock(&cond->mutex);
+
+   ret = sceKernelWaitSema(cond->sema, 1, 0);
+   if (ret < 0)
+      sceClibPrintf("Premature wakeup: %08X", ret);
+   pthread_mutex_lock(mutex);
+   return ret;
+#else
+   /* FIXME: stub */
+   sceKernelDelayThread(10000);
+   return 1;
+#endif
+}
+
+static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+#ifdef VITA
+   int ret = pthread_mutex_lock(&cond->mutex);
+   if (ret < 0)
+      return ret;
+   ++cond->waiting;
+   pthread_mutex_unlock(mutex);
+   pthread_mutex_unlock(&cond->mutex);
+
+   SceUInt timeout = 0;
+
+   timeout  = abstime->tv_sec;
+   timeout += abstime->tv_nsec / 1.0e6;
+
+   ret = sceKernelWaitSema(cond->sema, 1, &timeout);
+   if (ret < 0)
+      sceClibPrintf("Premature wakeup: %08X", ret);
+   pthread_mutex_lock(mutex);
+   return ret;
+
+#else
+   /* FIXME: stub */
+   return 1;
+#endif
+}
+
+static INLINE int pthread_cond_init(pthread_cond_t *cond,
+      const pthread_condattr_t *attr)
+{
+#ifdef VITA
+
+   pthread_mutex_init(&cond->mutex,NULL);
+
+   if (cond->mutex<0)
+      return cond->mutex;
+
+   snprintf(name_buffer, sizeof(name_buffer), "0x%08X", (unsigned int) cond);
+   cond->sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);
+
+   if (cond->sema < 0)
+   {
+      pthread_mutex_destroy(&cond->mutex);
+      return cond->sema;
+   }
+
+   cond->waiting = 0;
+
+   return 0;
+
+#else
+   /* FIXME: stub */
+   return 1;
+#endif
+}
+
+static INLINE int pthread_cond_signal(pthread_cond_t *cond)
+{
+#ifdef VITA
+       pthread_mutex_lock(&cond->mutex);
+       if (cond->waiting)
+   {
+               --cond->waiting;
+               sceKernelSignalSema(cond->sema, 1);
+       }
+       pthread_mutex_unlock(&cond->mutex);
+       return 0;
+#else
+   /* FIXME: stub */
+   return 1;
+#endif
+}
+
+static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+   /* FIXME: stub */
+   return 1;
+}
+
+static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
+{
+#ifdef VITA
+   int ret = sceKernelDeleteSema(cond->sema);
+   if (ret < 0)
+    return ret;
+
+   return sceKernelDeleteMutex(cond->mutex);
+#else
+  /* FIXME: stub */
+  return 1;
+#endif
+}
+
+static INLINE int pthread_detach(pthread_t thread)
+{
+   return 0;
+}
+
+static INLINE void pthread_exit(void *retval)
+{
+#ifdef VITA
+   sceKernelExitDeleteThread(sceKernelGetThreadId());
+#endif
+}
+
+static INLINE pthread_t pthread_self(void)
+{
+   /* zero 20-mar-2016: untested */
+   return sceKernelGetThreadId();
+}
+
+static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
+{
+        return t1 == t2;
+}
+
+#endif //_PSP_PTHREAD_WRAP__
diff --git a/deps/libretro-common/rthreads/rthreads.c b/deps/libretro-common/rthreads/rthreads.c
new file mode 100644 (file)
index 0000000..b923a8e
--- /dev/null
@@ -0,0 +1,935 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rthreads.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+#ifdef __unix__
+#ifndef __sun__
+#define _POSIX_C_SOURCE 199309
+#endif
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <boolean.h>
+#include <rthreads/rthreads.h>
+
+/* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32. Maybe only supported in MSVC>=2005  */
+
+#if defined(_WIN32) && !defined(RETRO_WIN32_USE_PTHREADS)
+#define USE_WIN32_THREADS
+#ifdef _XBOX
+#include <xtl.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */
+#endif
+#include <windows.h>
+#include <mmsystem.h>
+#endif
+#elif defined(GEKKO)
+#include <ogc/lwp_watchdog.h>
+#include "gx_pthread.h"
+#elif defined(_3DS)
+#include "ctr_pthread.h"
+#else
+#include <pthread.h>
+#include <time.h>
+#endif
+
+#if defined(VITA) || defined(BSD) || defined(ORBIS) || defined(__mips__) || defined(_3DS)
+#include <sys/time.h>
+#endif
+
+#ifdef __MACH__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
+struct thread_data
+{
+   void (*func)(void*);
+   void *userdata;
+};
+
+struct sthread
+{
+#ifdef USE_WIN32_THREADS
+   HANDLE thread;
+   DWORD id;
+#else
+   pthread_t id;
+#endif
+};
+
+struct slock
+{
+#ifdef USE_WIN32_THREADS
+   CRITICAL_SECTION lock;
+#else
+   pthread_mutex_t lock;
+#endif
+};
+
+#ifdef USE_WIN32_THREADS
+/* The syntax we'll use is mind-bending unless we use a struct. Plus, we might want to store more info later */
+/* This will be used as a linked list immplementing a queue of waiting threads */
+struct queue_entry
+{
+   struct queue_entry *next;
+};
+#endif
+
+struct scond
+{
+#ifdef USE_WIN32_THREADS
+   /* With this implementation of scond, we don't have any way of waking
+    * (or even identifying) specific threads
+    * But we need to wake them in the order indicated by the queue.
+    * This potato token will get get passed around every waiter.
+    * The bearer can test whether he's next, and hold onto the potato if he is.
+    * When he's done he can then put it back into play to progress
+    * the queue further */
+   HANDLE hot_potato;
+
+   /* The primary signalled event. Hot potatoes are passed until this is set. */
+   HANDLE event;
+
+   /* the head of the queue; NULL if queue is empty */
+   struct queue_entry *head;
+
+   /* equivalent to the queue length */
+   int waiters;
+
+   /* how many waiters in the queue have been conceptually wakened by signals
+    * (even if we haven't managed to actually wake them yet) */
+   int wakens;
+
+   /* used to control access to this scond, in case the user fails */
+   CRITICAL_SECTION cs;
+
+#else
+   pthread_cond_t cond;
+#endif
+};
+
+#ifdef USE_WIN32_THREADS
+static DWORD CALLBACK thread_wrap(void *data_)
+#else
+static void *thread_wrap(void *data_)
+#endif
+{
+   struct thread_data *data = (struct thread_data*)data_;
+   if (!data)
+          return 0;
+   data->func(data->userdata);
+   free(data);
+   return 0;
+}
+
+/**
+ * sthread_create:
+ * @start_routine           : thread entry callback function
+ * @userdata                : pointer to userdata that will be made
+ *                            available in thread entry callback function
+ *
+ * Create a new thread.
+ *
+ * Returns: pointer to new thread if successful, otherwise NULL.
+ */
+sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
+{
+       return sthread_create_with_priority(thread_func, userdata, 0);
+}
+
+/* TODO/FIXME - this needs to be implemented for Switch/3DS */
+#if !defined(SWITCH) && !defined(USE_WIN32_THREADS) && !defined(_3DS) && !defined(GEKKO) && !defined(__HAIKU__) && !defined(EMSCRIPTEN)
+#define HAVE_THREAD_ATTR
+#endif
+
+/**
+ * sthread_create_with_priority:
+ * @start_routine           : thread entry callback function
+ * @userdata                : pointer to userdata that will be made
+ *                            available in thread entry callback function
+ * @thread_priority         : thread priority hint value from [1-100]
+ *
+ * Create a new thread. It is possible for the caller to give a hint
+ * for the thread's priority from [1-100]. Any passed in @thread_priority
+ * values that are outside of this range will cause sthread_create() to
+ * create a new thread using the operating system's default thread
+ * priority.
+ *
+ * Returns: pointer to new thread if successful, otherwise NULL.
+ */
+sthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority)
+{
+#ifdef HAVE_THREAD_ATTR
+   pthread_attr_t thread_attr;
+   bool thread_attr_needed  = false;
+#endif
+   bool thread_created      = false;
+   struct thread_data *data = NULL;
+   sthread_t *thread        = (sthread_t*)malloc(sizeof(*thread));
+
+   if (!thread)
+      return NULL;
+
+   if (!(data = (struct thread_data*)malloc(sizeof(*data))))
+   {
+      free(thread);
+      return NULL;
+   }
+
+   data->func               = thread_func;
+   data->userdata           = userdata;
+
+   thread->id               = 0;
+#ifdef USE_WIN32_THREADS
+   thread->thread           = CreateThread(NULL, 0, thread_wrap,
+         data, 0, &thread->id);
+   thread_created           = !!thread->thread;
+#else
+#ifdef HAVE_THREAD_ATTR
+   pthread_attr_init(&thread_attr);
+
+   if ((thread_priority >= 1) && (thread_priority <= 100))
+   {
+      struct sched_param sp;
+      memset(&sp, 0, sizeof(struct sched_param));
+      sp.sched_priority = thread_priority;
+      pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
+      pthread_attr_setschedparam(&thread_attr, &sp);
+
+      thread_attr_needed = true;
+   }
+
+#if defined(VITA)
+   pthread_attr_setstacksize(&thread_attr , 0x10000 );
+   thread_attr_needed = true;
+#elif defined(__APPLE__)
+   /* Default stack size on Apple is 512Kb; 
+    * for PS2 disc scanning and other reasons, we'd like 2MB. */
+   pthread_attr_setstacksize(&thread_attr , 0x200000 );
+   thread_attr_needed = true;
+#endif
+
+   if (thread_attr_needed)
+      thread_created = pthread_create(&thread->id, &thread_attr, thread_wrap, data) == 0;
+   else
+      thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
+
+   pthread_attr_destroy(&thread_attr);
+#else
+   thread_created    = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
+#endif
+
+#endif
+
+   if (thread_created)
+      return thread;
+   free(data);
+   free(thread);
+   return NULL;
+}
+
+/**
+ * sthread_detach:
+ * @thread                  : pointer to thread object
+ *
+ * Detach a thread. When a detached thread terminates, its
+ * resources are automatically released back to the system
+ * without the need for another thread to join with the
+ * terminated thread.
+ *
+ * Returns: 0 on success, otherwise it returns a non-zero error number.
+ */
+int sthread_detach(sthread_t *thread)
+{
+#ifdef USE_WIN32_THREADS
+   CloseHandle(thread->thread);
+   free(thread);
+   return 0;
+#else
+   int ret = pthread_detach(thread->id);
+   free(thread);
+   return ret;
+#endif
+}
+
+/**
+ * sthread_join:
+ * @thread                  : pointer to thread object
+ *
+ * Join with a terminated thread. Waits for the thread specified by
+ * @thread to terminate. If that thread has already terminated, then
+ * it will return immediately. The thread specified by @thread must
+ * be joinable.
+ *
+ * Returns: 0 on success, otherwise it returns a non-zero error number.
+ */
+void sthread_join(sthread_t *thread)
+{
+   if (!thread)
+      return;
+#ifdef USE_WIN32_THREADS
+   WaitForSingleObject(thread->thread, INFINITE);
+   CloseHandle(thread->thread);
+#else
+   pthread_join(thread->id, NULL);
+#endif
+   free(thread);
+}
+
+#if !defined(GEKKO)
+/**
+ * sthread_isself:
+ * @thread                  : pointer to thread object
+ *
+ * Returns: true (1) if calling thread is the specified thread
+ */
+bool sthread_isself(sthread_t *thread)
+{
+#ifdef USE_WIN32_THREADS
+   return thread ? GetCurrentThreadId() == thread->id        : false;
+#else
+   return thread ? pthread_equal(pthread_self(), thread->id) : false;
+#endif
+}
+#endif
+
+/**
+ * slock_new:
+ *
+ * Create and initialize a new mutex. Must be manually
+ * freed.
+ *
+ * Returns: pointer to a new mutex if successful, otherwise NULL.
+ **/
+slock_t *slock_new(void)
+{
+   slock_t      *lock = (slock_t*)calloc(1, sizeof(*lock));
+   if (!lock)
+      return NULL;
+#ifdef USE_WIN32_THREADS
+   InitializeCriticalSection(&lock->lock);
+#else
+   if (pthread_mutex_init(&lock->lock, NULL) != 0)
+   {
+      free(lock);
+      return NULL;
+   }
+#endif
+   return lock;
+}
+
+/**
+ * slock_free:
+ * @lock                    : pointer to mutex object
+ *
+ * Frees a mutex.
+ **/
+void slock_free(slock_t *lock)
+{
+   if (!lock)
+      return;
+
+#ifdef USE_WIN32_THREADS
+   DeleteCriticalSection(&lock->lock);
+#else
+   pthread_mutex_destroy(&lock->lock);
+#endif
+   free(lock);
+}
+
+/**
+ * slock_lock:
+ * @lock                    : pointer to mutex object
+ *
+ * Locks a mutex. If a mutex is already locked by
+ * another thread, the calling thread shall block until
+ * the mutex becomes available.
+**/
+void slock_lock(slock_t *lock)
+{
+   if (!lock)
+      return;
+#ifdef USE_WIN32_THREADS
+   EnterCriticalSection(&lock->lock);
+#else
+   pthread_mutex_lock(&lock->lock);
+#endif
+}
+
+/**
+ * slock_try_lock:
+ * @lock                    : pointer to mutex object
+ *
+ * Attempts to lock a mutex. If a mutex is already locked by
+ * another thread, return false.  If the lock is acquired, return true.
+**/
+bool slock_try_lock(slock_t *lock)
+{
+#ifdef USE_WIN32_THREADS
+   return lock && TryEnterCriticalSection(&lock->lock);
+#else
+   return lock && (pthread_mutex_trylock(&lock->lock) == 0);
+#endif
+}
+
+/**
+ * slock_unlock:
+ * @lock                    : pointer to mutex object
+ *
+ * Unlocks a mutex.
+ **/
+void slock_unlock(slock_t *lock)
+{
+   if (!lock)
+      return;
+#ifdef USE_WIN32_THREADS
+   LeaveCriticalSection(&lock->lock);
+#else
+   pthread_mutex_unlock(&lock->lock);
+#endif
+}
+
+/**
+ * scond_new:
+ *
+ * Creates and initializes a condition variable. Must
+ * be manually freed.
+ *
+ * Returns: pointer to new condition variable on success,
+ * otherwise NULL.
+ **/
+scond_t *scond_new(void)
+{
+   scond_t      *cond = (scond_t*)calloc(1, sizeof(*cond));
+
+   if (!cond)
+      return NULL;
+
+#ifdef USE_WIN32_THREADS
+   /* This is very complex because recreating condition variable semantics
+    * with Win32 parts is not easy.
+    *
+    * The main problem is that a condition variable can't be used to
+    * "pre-wake" a thread (it will get wakened only after it's waited).
+    *
+    * Whereas a win32 event can pre-wake a thread (the event will be set
+    * in advance, so a 'waiter' won't even have to wait on it).
+    *
+    * Keep in mind a condition variable can apparently pre-wake a thread,
+    * insofar as spurious wakeups are always possible,
+    * but nobody will be expecting this and it does not need to be simulated.
+    *
+    * Moreover, we won't be doing this, because it counts as a spurious wakeup
+    * -- someone else with a genuine claim must get wakened, in any case.
+    *
+    * Therefore we choose to wake only one of the correct waiting threads.
+    * So at the very least, we need to do something clever. But there's
+    * bigger problems.
+    * We don't even have a straightforward way in win32 to satisfy
+    * pthread_cond_wait's atomicity requirement. The bulk of this
+    * algorithm is solving that.
+    *
+    * Note: We might could simplify this using vista+ condition variables,
+    * but we wanted an XP compatible solution. */
+   if (!(cond->event      = CreateEvent(NULL, FALSE, FALSE, NULL)))
+      goto error;
+   if (!(cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL)))
+   {
+      CloseHandle(cond->event);
+      goto error;
+   }
+
+   InitializeCriticalSection(&cond->cs);
+#else
+   if (pthread_cond_init(&cond->cond, NULL) != 0)
+      goto error;
+#endif
+
+   return cond;
+
+error:
+   free(cond);
+   return NULL;
+}
+
+/**
+ * scond_free:
+ * @cond                    : pointer to condition variable object
+ *
+ * Frees a condition variable.
+**/
+void scond_free(scond_t *cond)
+{
+   if (!cond)
+      return;
+
+#ifdef USE_WIN32_THREADS
+   CloseHandle(cond->event);
+   CloseHandle(cond->hot_potato);
+   DeleteCriticalSection(&cond->cs);
+#else
+   pthread_cond_destroy(&cond->cond);
+#endif
+   free(cond);
+}
+
+#ifdef USE_WIN32_THREADS
+static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds)
+{
+   struct queue_entry myentry;
+   struct queue_entry **ptr;
+
+#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
+   static LARGE_INTEGER performanceCounterFrequency;
+   LARGE_INTEGER tsBegin;
+   static bool first_init  = true;
+#else
+   static bool beginPeriod = false;
+   DWORD tsBegin;
+#endif
+   DWORD waitResult;
+   DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head,
+                                             we don't do the hot potato stuff,
+                                             so this timeout needs presetting. */
+
+   /* Reminder: `lock` is held before this is called. */
+   /* however, someone else may have called scond_signal without the lock. soo... */
+   EnterCriticalSection(&cond->cs);
+
+   /* since this library is meant for realtime game software
+    * I have no problem setting this to 1 and forgetting about it. */
+#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
+   if (first_init)
+   {
+      performanceCounterFrequency.QuadPart = 0;
+      first_init = false;
+   }
+
+   if (performanceCounterFrequency.QuadPart == 0)
+      QueryPerformanceFrequency(&performanceCounterFrequency);
+#else
+   if (!beginPeriod)
+   {
+      beginPeriod = true;
+      timeBeginPeriod(1);
+   }
+#endif
+
+   /* Now we can take a good timestamp for use in faking the timeout ourselves. */
+   /* But don't bother unless we need to (to save a little time) */
+   if (dwMilliseconds != INFINITE)
+#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
+      QueryPerformanceCounter(&tsBegin);
+#else
+      tsBegin = timeGetTime();
+#endif
+
+   /* add ourselves to a queue of waiting threads */
+   ptr = &cond->head;
+
+   /* walk to the end of the linked list */
+   while (*ptr)
+      ptr       = &((*ptr)->next);
+
+   *ptr         = &myentry;
+   myentry.next = NULL;
+
+   cond->waiters++;
+
+   /* now the conceptual lock release and condition block are supposed to be atomic.
+    * we can't do that in Windows, but we can simulate the effects by using
+    * the queue, by the following analysis:
+    * What happens if they aren't atomic?
+    *
+    * 1. a signaller can rush in and signal, expecting a waiter to get it;
+    * but the waiter wouldn't, because he isn't blocked yet.
+    * Solution: Win32 events make this easy. The event will sit there enabled
+    *
+    * 2. a signaller can rush in and signal, and then turn right around and wait.
+    * Solution: the signaller will get queued behind the waiter, who's
+    * enqueued before he releases the mutex. */
+
+   /* It's my turn if I'm the head of the queue.
+    * Check to see if it's my turn. */
+   while (cond->head != &myentry)
+   {
+      /* It isn't my turn: */
+      DWORD timeout = INFINITE;
+
+      /* As long as someone is even going to be able to wake up
+       * when they receive the potato, keep it going round. */
+      if (cond->wakens > 0)
+         SetEvent(cond->hot_potato);
+
+      /* Assess the remaining timeout time */
+      if (dwMilliseconds != INFINITE)
+      {
+#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)
+         LARGE_INTEGER now;
+         LONGLONG elapsed;
+
+         QueryPerformanceCounter(&now);
+         elapsed  = now.QuadPart - tsBegin.QuadPart;
+         elapsed *= 1000;
+         elapsed /= performanceCounterFrequency.QuadPart;
+#else
+         DWORD now     = timeGetTime();
+         DWORD elapsed = now - tsBegin;
+#endif
+
+         /* Try one last time with a zero timeout (keeps the code simpler) */
+         if (elapsed > dwMilliseconds)
+            elapsed = dwMilliseconds;
+
+         timeout = dwMilliseconds - elapsed;
+      }
+
+      /* Let someone else go */
+      LeaveCriticalSection(&lock->lock);
+      LeaveCriticalSection(&cond->cs);
+
+      /* Wait a while to catch the hot potato..
+       * someone else should get a chance to go */
+      /* After all, it isn't my turn (and it must be someone else's) */
+      Sleep(0);
+      waitResult = WaitForSingleObject(cond->hot_potato, timeout);
+
+      /* I should come out of here with the main lock taken */
+      EnterCriticalSection(&lock->lock);
+      EnterCriticalSection(&cond->cs);
+
+      if (waitResult == WAIT_TIMEOUT)
+      {
+         /* Out of time! Now, let's think about this. I do have the potato now--
+          * maybe it's my turn, and I have the event?
+          * If that's the case, I could proceed right now without aborting
+          * due to timeout.
+          *
+          * However.. I DID wait a real long time. The caller was willing
+          * to wait that long.
+          *
+          * I choose to give him one last chance with a zero timeout
+          * in the next step
+          */
+         if (cond->head == &myentry)
+         {
+            dwFinalTimeout = 0;
+            break;
+         }
+         else
+         {
+            /* It's not our turn and we're out of time. Give up.
+             * Remove ourself from the queue and bail. */
+            struct queue_entry *curr = cond->head;
+
+            while (curr->next != &myentry)
+               curr = curr->next;
+            curr->next = myentry.next;
+            cond->waiters--;
+            LeaveCriticalSection(&cond->cs);
+            return false;
+         }
+      }
+
+   }
+
+   /* It's my turn now -- and I hold the potato */
+
+   /* I still have the main lock, in any case */
+   /* I need to release it so that someone can set the event */
+   LeaveCriticalSection(&lock->lock);
+   LeaveCriticalSection(&cond->cs);
+
+   /* Wait for someone to actually signal this condition */
+   /* We're the only waiter waiting on the event right now -- everyone else
+    * is waiting on something different */
+   waitResult = WaitForSingleObject(cond->event, dwFinalTimeout);
+
+   /* Take the main lock so we can do work. Nobody else waits on this lock
+    * for very long, so even though it's GO TIME we won't have to wait long */
+   EnterCriticalSection(&lock->lock);
+   EnterCriticalSection(&cond->cs);
+
+   /* Remove ourselves from the queue */
+   cond->head = myentry.next;
+   cond->waiters--;
+
+   if (waitResult == WAIT_TIMEOUT)
+   {
+      /* Oops! ran out of time in the final wait. Just bail. */
+      LeaveCriticalSection(&cond->cs);
+      return false;
+   }
+
+   /* If any other wakenings are pending, go ahead and set it up  */
+   /* There may actually be no waiters. That's OK. The first waiter will come in,
+    * find it's his turn, and immediately get the signaled event */
+   cond->wakens--;
+   if (cond->wakens > 0)
+   {
+      SetEvent(cond->event);
+
+      /* Progress the queue: Put the hot potato back into play. It'll be
+       * tossed around until next in line gets it */
+      SetEvent(cond->hot_potato);
+   }
+
+   LeaveCriticalSection(&cond->cs);
+   return true;
+}
+#endif
+
+/**
+ * scond_wait:
+ * @cond                    : pointer to condition variable object
+ * @lock                    : pointer to mutex object
+ *
+ * Block on a condition variable (i.e. wait on a condition).
+ **/
+void scond_wait(scond_t *cond, slock_t *lock)
+{
+#ifdef USE_WIN32_THREADS
+   _scond_wait_win32(cond, lock, INFINITE);
+#else
+   pthread_cond_wait(&cond->cond, &lock->lock);
+#endif
+}
+
+/**
+ * scond_broadcast:
+ * @cond                    : pointer to condition variable object
+ *
+ * Broadcast a condition. Unblocks all threads currently blocked
+ * on the specified condition variable @cond.
+ **/
+int scond_broadcast(scond_t *cond)
+{
+#ifdef USE_WIN32_THREADS
+   /* Remember, we currently have mutex */
+   if (cond->waiters != 0)
+   {
+      /* Awaken everything which is currently queued up */
+      if (cond->wakens == 0)
+         SetEvent(cond->event);
+      cond->wakens = cond->waiters;
+
+      /* Since there is now at least one pending waken, the potato must be in play */
+      SetEvent(cond->hot_potato);
+   }
+   return 0;
+#else
+   return pthread_cond_broadcast(&cond->cond);
+#endif
+}
+
+/**
+ * scond_signal:
+ * @cond                    : pointer to condition variable object
+ *
+ * Signal a condition. Unblocks at least one of the threads currently blocked
+ * on the specified condition variable @cond.
+ **/
+void scond_signal(scond_t *cond)
+{
+#ifdef USE_WIN32_THREADS
+
+   /* Unfortunately, pthread_cond_signal does not require that the
+    * lock be held in advance */
+   /* To avoid stomping on the condvar from other threads, we need
+    * to control access to it with this */
+   EnterCriticalSection(&cond->cs);
+
+   /* remember: we currently have mutex */
+   if (cond->waiters == 0)
+   {
+      LeaveCriticalSection(&cond->cs);
+      return;
+   }
+
+   /* wake up the next thing in the queue */
+   if (cond->wakens == 0)
+      SetEvent(cond->event);
+
+   cond->wakens++;
+
+   /* The data structure is done being modified.. I think we can leave the CS now.
+    * This would prevent some other thread from receiving the hot potato and then
+    * immediately stalling for the critical section.
+    * But remember, we were trying to replicate a semantic where this entire
+    * scond_signal call was controlled (by the user) by a lock.
+    * So in case there's trouble with this, we can move it after SetEvent() */
+   LeaveCriticalSection(&cond->cs);
+
+   /* Since there is now at least one pending waken, the potato must be in play */
+   SetEvent(cond->hot_potato);
+
+#else
+   pthread_cond_signal(&cond->cond);
+#endif
+}
+
+/**
+ * scond_wait_timeout:
+ * @cond                    : pointer to condition variable object
+ * @lock                    : pointer to mutex object
+ * @timeout_us              : timeout (in microseconds)
+ *
+ * Try to block on a condition variable (i.e. wait on a condition) until
+ * @timeout_us elapses.
+ *
+ * Returns: false (0) if timeout elapses before condition variable is
+ * signaled or broadcast, otherwise true (1).
+ **/
+bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
+{
+#ifdef USE_WIN32_THREADS
+   /* How to convert a microsecond (us) timeout to millisecond (ms)?
+    *
+    * Someone asking for a 0 timeout clearly wants immediate timeout.
+    * Someone asking for a 1 timeout clearly wants an actual timeout
+    * of the minimum length */
+   /* The implementation of a 0 timeout here with pthreads is sketchy.
+    * It isn't clear what happens if pthread_cond_timedwait is called with NOW.
+    * Moreover, it is possible that this thread gets pre-empted after the
+    * clock_gettime but before the pthread_cond_timedwait.
+    * In order to help smoke out problems caused by this strange usage,
+    * let's treat a 0 timeout as always timing out.
+    */
+   if (timeout_us == 0)
+      return false;
+   else if (timeout_us < 1000)
+      return _scond_wait_win32(cond, lock, 1);
+   /* Someone asking for 1000 or 1001 timeout shouldn't
+    * accidentally get 2ms. */
+   return _scond_wait_win32(cond, lock, timeout_us / 1000);
+#else
+   int64_t seconds, remainder;
+   struct timespec now;
+#ifdef __MACH__
+   /* OSX doesn't have clock_gettime. */
+   clock_serv_t cclock;
+   mach_timespec_t mts;
+   host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+   clock_get_time(cclock, &mts);
+   mach_port_deallocate(mach_task_self(), cclock);
+   now.tv_sec = mts.tv_sec;
+   now.tv_nsec = mts.tv_nsec;
+#elif !defined(__PSL1GHT__) && defined(__PS3__)
+   sys_time_sec_t s;
+   sys_time_nsec_t n;
+   sys_time_get_current_time(&s, &n);
+   now.tv_sec            = s;
+   now.tv_nsec           = n;
+#elif defined(PS2)
+   int tickms            = ps2_clock();
+   now.tv_sec            = tickms / 1000;
+   now.tv_nsec           = tickms * 1000;
+#elif !defined(DINGUX_BETA) && (defined(__mips__) || defined(VITA) || defined(_3DS))
+   struct timeval tm;
+   gettimeofday(&tm, NULL);
+   now.tv_sec            = tm.tv_sec;
+   now.tv_nsec           = tm.tv_usec * 1000;
+#elif defined(RETRO_WIN32_USE_PTHREADS)
+   _ftime64_s(&now);
+#elif defined(GEKKO)
+   /* Avoid gettimeofday due to it being reported to be broken */
+   const uint64_t tickms = gettime() / TB_TIMER_CLOCK;
+   now.tv_sec            = tickms / 1000;
+   now.tv_nsec           = tickms * 1000;
+#else
+   clock_gettime(CLOCK_REALTIME, &now);
+#endif
+
+   seconds              = timeout_us / INT64_C(1000000);
+   remainder            = timeout_us % INT64_C(1000000);
+
+   now.tv_sec          += seconds;
+   now.tv_nsec         += remainder * INT64_C(1000);
+
+   if (now.tv_nsec > 1000000000)
+   {
+      now.tv_nsec      -= 1000000000;
+      now.tv_sec       += 1;
+   }
+
+   return (pthread_cond_timedwait(&cond->cond, &lock->lock, &now) == 0);
+#endif
+}
+
+#ifdef HAVE_THREAD_STORAGE
+bool sthread_tls_create(sthread_tls_t *tls)
+{
+#ifdef USE_WIN32_THREADS
+   return (*tls = TlsAlloc()) != TLS_OUT_OF_INDEXES;
+#else
+   return pthread_key_create((pthread_key_t*)tls, NULL) == 0;
+#endif
+}
+
+bool sthread_tls_delete(sthread_tls_t *tls)
+{
+#ifdef USE_WIN32_THREADS
+   return TlsFree(*tls) != 0;
+#else
+   return pthread_key_delete(*tls) == 0;
+#endif
+}
+
+void *sthread_tls_get(sthread_tls_t *tls)
+{
+#ifdef USE_WIN32_THREADS
+   return TlsGetValue(*tls);
+#else
+   return pthread_getspecific(*tls);
+#endif
+}
+
+bool sthread_tls_set(sthread_tls_t *tls, const void *data)
+{
+#ifdef USE_WIN32_THREADS
+   return TlsSetValue(*tls, (void*)data) != 0;
+#else
+   return pthread_setspecific(*tls, data) == 0;
+#endif
+}
+#endif
+
+uintptr_t sthread_get_thread_id(sthread_t *thread)
+{
+   if (thread)
+      return (uintptr_t)thread->id;
+   return 0;
+}
+
+uintptr_t sthread_get_current_thread_id(void)
+{
+#ifdef USE_WIN32_THREADS
+   return (uintptr_t)GetCurrentThreadId();
+#else
+   return (uintptr_t)pthread_self();
+#endif
+}
diff --git a/deps/libretro-common/rthreads/tpool.c b/deps/libretro-common/rthreads/tpool.c
new file mode 100644 (file)
index 0000000..1e091a9
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2010-2020 The RetroArch team
+ * Copyright (c) 2017 John Schember <john@nachtimwald.com>
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (tpool.c).
+ * ---------------------------------------------------------------------------------------
+ * 
+ * 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 <stdlib.h>
+#include <boolean.h>
+
+#include <rthreads/rthreads.h>
+#include <rthreads/tpool.h>
+
+/* Work object which will sit in a queue
+ * waiting for the pool to process it.
+ *
+ * It is a singly linked list acting as a FIFO queue. */
+struct tpool_work
+{
+   thread_func_t      func;  /* Function to be called. */
+   void              *arg;   /* Data to be passed to func. */
+   struct tpool_work *next;  /* Next work item in the queue. */
+};
+typedef struct tpool_work tpool_work_t;
+
+struct tpool
+{
+   tpool_work_t    *work_first;   /* First work item in the work queue. */
+   tpool_work_t    *work_last;    /* Last work item in the work queue. */
+   slock_t         *work_mutex;   /* Mutex protecting inserting and removing work from the work queue. */
+   scond_t         *work_cond;    /* Conditional to signal when there is work to process. */
+   scond_t         *working_cond; /* Conditional to signal when there is no work processing.
+                                       This will also signal when there are no threads running. */
+   size_t           working_cnt;  /* The number of threads processing work (Not waiting for work). */
+   size_t           thread_cnt;   /* Total number of threads within the pool. */
+   bool             stop;         /* Marker to tell the work threads to exit. */
+};
+
+static tpool_work_t *tpool_work_create(thread_func_t func, void *arg)
+{
+   tpool_work_t *work;
+
+   if (!func)
+      return NULL;
+
+   work       = (tpool_work_t*)calloc(1, sizeof(*work));
+   work->func = func;
+   work->arg  = arg;
+   work->next = NULL;
+   return work;
+}
+
+static void tpool_work_destroy(tpool_work_t *work)
+{
+   if (work)
+      free(work);
+}
+
+/* Pull the first work item out of the queue. */
+static tpool_work_t *tpool_work_get(tpool_t *tp)
+{
+   tpool_work_t *work;
+
+   if (!tp)
+      return NULL;
+
+   work = tp->work_first;
+   if (!work)
+      return NULL;
+
+   if (!work->next)
+   {
+      tp->work_first = NULL;
+      tp->work_last  = NULL;
+   }
+   else
+      tp->work_first = work->next;
+
+   return work;
+}
+
+static void tpool_worker(void *arg)
+{
+   tpool_work_t *work = NULL;
+   tpool_t      *tp   = (tpool_t*)arg;
+
+   for (;;)
+   {
+      slock_lock(tp->work_mutex);
+      /* Keep running until told to stop. */
+      if (tp->stop)
+         break;
+
+      /* If there is no work in the queue wait in the conditional until
+       * there is work to take. */
+      if (!tp->work_first)
+         scond_wait(tp->work_cond, tp->work_mutex);
+
+      /* Try to pull work from the queue. */
+      work = tpool_work_get(tp);
+      tp->working_cnt++;
+      slock_unlock(tp->work_mutex);
+
+      /* Call the work function and let it process.
+       *
+       * work can legitimately be NULL. Since multiple threads from the pool
+       * will wake when there is work, a thread might not get any work. 1
+       * piece of work and 2 threads, both will wake but with 1 only work 1
+       * will get the work and the other won't.
+       *
+       * working_cnt has been increment and work could be NULL. While it's
+       * not true there is work processing the thread is considered working
+       * because it's not waiting in the conditional. Pedantic but...
+       */
+      if (work)
+      {
+         work->func(work->arg);
+         tpool_work_destroy(work);
+      }
+
+      slock_lock(tp->work_mutex);
+      tp->working_cnt--;
+      /* Since we're in a lock no work can be added or removed form the queue.
+       * Also, the working_cnt can't be changed (except the thread holding the lock).
+       * At this point if there isn't any work processing and if there is no work
+       * signal this is the case. */
+      if (!tp->stop && tp->working_cnt == 0 && !tp->work_first)
+         scond_signal(tp->working_cond);
+      slock_unlock(tp->work_mutex);
+   }
+
+   tp->thread_cnt--;
+   if (tp->thread_cnt == 0)
+      scond_signal(tp->working_cond);
+   slock_unlock(tp->work_mutex);
+}
+
+tpool_t *tpool_create(size_t num)
+{
+   tpool_t   *tp;
+   sthread_t *thread;
+   size_t     i;
+
+   if (num == 0)
+      num = 2;
+
+   tp               = (tpool_t*)calloc(1, sizeof(*tp));
+   tp->thread_cnt   = num;
+
+   tp->work_mutex   = slock_new();
+   tp->work_cond    = scond_new();
+   tp->working_cond = scond_new();
+
+   tp->work_first   = NULL;
+   tp->work_last    = NULL;
+
+   /* Create the requested number of thread and detach them. */
+   for (i = 0; i < num; i++)
+   {
+      thread = sthread_create(tpool_worker, tp);
+      sthread_detach(thread);
+   }
+
+   return tp;
+}
+
+void tpool_destroy(tpool_t *tp)
+{
+   tpool_work_t *work;
+   tpool_work_t *work2;
+
+   if (!tp)
+      return;
+
+   /* Take all work out of the queue and destroy it. */
+   slock_lock(tp->work_mutex);
+   work = tp->work_first;
+   while (work)
+   {
+      work2 = work->next;
+      tpool_work_destroy(work);
+      work = work2;
+   }
+
+   /* Tell the worker threads to stop. */
+   tp->stop = true;
+   scond_broadcast(tp->work_cond);
+   slock_unlock(tp->work_mutex);
+
+   /* Wait for all threads to stop. */
+   tpool_wait(tp);
+
+   slock_free(tp->work_mutex);
+   scond_free(tp->work_cond);
+   scond_free(tp->working_cond);
+
+   free(tp);
+}
+
+bool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg)
+{
+   tpool_work_t *work;
+
+   if (!tp)
+      return false;
+
+   work = tpool_work_create(func, arg);
+   if (!work)
+      return false;
+
+   slock_lock(tp->work_mutex);
+   if (!tp->work_first)
+   {
+      tp->work_first      = work;
+      tp->work_last       = tp->work_first;
+   }
+   else
+   {
+      tp->work_last->next = work;
+      tp->work_last       = work;
+   }
+
+   scond_broadcast(tp->work_cond);
+   slock_unlock(tp->work_mutex);
+
+   return true;
+}
+
+void tpool_wait(tpool_t *tp)
+{
+   if (!tp)
+      return;
+
+   slock_lock(tp->work_mutex);
+
+   for (;;)
+   {
+      /* working_cond is dual use. It signals when we're not stopping but the
+       * working_cnt is 0 indicating there isn't any work processing. If we
+       * are stopping it will trigger when there aren't any threads running. */
+      if ((!tp->stop && tp->working_cnt != 0) || (tp->stop && tp->thread_cnt != 0))
+         scond_wait(tp->working_cond, tp->work_mutex);
+      else
+         break;
+   }
+
+   slock_unlock(tp->work_mutex);
+}
diff --git a/deps/libretro-common/rthreads/wiiu_pthread.h b/deps/libretro-common/rthreads/wiiu_pthread.h
new file mode 100644 (file)
index 0000000..fa9ec81
--- /dev/null
@@ -0,0 +1,167 @@
+/* Copyright  (C) 2010-2016 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (wiiu_pthread.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 _WIIU_PTHREAD_WRAP_WIIU_
+#define _WIIU_PTHREAD_WRAP_WIIU_
+
+#include <retro_inline.h>
+#include <wiiu/os/condition.h>
+#include <wiiu/os/thread.h>
+#include <wiiu/os/mutex.h>
+#include <malloc.h>
+#define STACKSIZE (8 * 1024)
+
+typedef OSThread* pthread_t;
+typedef OSMutex* pthread_mutex_t;
+typedef void* pthread_mutexattr_t;
+typedef int pthread_attr_t;
+typedef OSCondition* pthread_cond_t;
+typedef OSCondition* pthread_condattr_t;
+
+static INLINE int pthread_create(pthread_t *thread,
+      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
+{
+   OSThread *t = memalign(8, sizeof(OSThread));
+   void *stack = memalign(32, STACKSIZE);
+   bool ret = OSCreateThread(t, (OSThreadEntryPointFn)start_routine, 
+      (uint32_t)arg, NULL, (void*)(((uint32_t)stack)+STACKSIZE), STACKSIZE, 8, OS_THREAD_ATTRIB_AFFINITY_ANY);
+   if(ret == true)
+   {
+      OSResumeThread(t);
+      *thread = t;
+   }
+   else
+      *thread = NULL;
+   return (ret == true) ? 0 : -1;
+}
+
+static INLINE pthread_t pthread_self(void)
+{
+   return OSGetCurrentThread();
+}
+
+static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
+      const pthread_mutexattr_t *attr)
+{
+   OSMutex *m = malloc(sizeof(OSMutex));
+   OSInitMutex(m);
+   *mutex = m;
+   return 0;
+}
+
+static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+   if(*mutex)
+      free(*mutex);
+   *mutex = NULL;
+   return 0;
+}
+
+static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+   OSLockMutex(*mutex);
+   return 0;
+}
+
+static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+   OSUnlockMutex(*mutex);
+   return 0;
+}
+
+static INLINE void pthread_exit(void *retval)
+{
+   (void)retval;
+   OSExitThread(0);
+}
+
+static INLINE int pthread_detach(pthread_t thread)
+{
+   OSDetachThread(thread);
+   return 0;
+}
+
+static INLINE int pthread_join(pthread_t thread, void **retval)
+{
+   (void)retval;
+   bool ret = OSJoinThread(thread, NULL);
+   if(ret == true)
+   {
+      free(thread->stackEnd);
+      free(thread);
+   }
+   return (ret == true) ? 0 : -1;
+}
+
+static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+   return OSTryLockMutex(*mutex);
+}
+
+static INLINE int pthread_cond_wait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex)
+{
+   OSWaitCond(*cond, *mutex);
+   return 0;
+}
+
+static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+   //FIXME: actual timeout needed
+   (void)abstime;
+   return pthread_cond_wait(cond, mutex);
+}
+
+static INLINE int pthread_cond_init(pthread_cond_t *cond,
+      const pthread_condattr_t *attr)
+{
+   OSCondition *c = malloc(sizeof(OSCondition));
+   OSInitCond(c);
+   *cond = c;
+   return 0;
+}
+
+static INLINE int pthread_cond_signal(pthread_cond_t *cond)
+{
+   OSSignalCond(*cond);
+   return 0;
+}
+
+static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+   //FIXME: no OS equivalent
+   (void)cond;
+   return 0;
+}
+
+static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
+{
+   if(*cond)
+      free(*cond);
+   *cond = NULL;
+   return 0;
+}
+
+extern int pthread_equal(pthread_t t1, pthread_t t2);
+
+#endif
diff --git a/deps/libretro-common/rthreads/xenon_sdl_threads.c b/deps/libretro-common/rthreads/xenon_sdl_threads.c
new file mode 100644 (file)
index 0000000..186f9ec
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (xenon_sdl_threads.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+/* libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;) */
+
+#include "SDL_thread.h"
+#include "SDL_mutex.h"
+#include <stdlib.h>
+#include <boolean.h>
+
+SDL_cond *SDL_CreateCond(void)
+{
+   bool *sleeping = calloc(1, sizeof(*sleeping));
+   return (SDL_cond*)sleeping;
+}
+
+void SDL_DestroyCond(SDL_cond *sleeping)
+{
+   free(sleeping);
+}
+
+int SDL_CondWait(SDL_cond *cond, SDL_mutex *lock)
+{
+   (void)lock;
+   volatile bool *sleeping = (volatile bool*)cond;
+
+   SDL_mutexV(lock);
+   *sleeping = true;
+   while (*sleeping); /* Yeah, we all love busyloops don't we? ._. */
+   SDL_mutexP(lock);
+
+   return 0;
+}
+
+int SDL_CondSignal(SDL_cond *cond)
+{
+   *(volatile bool*)cond = false;
+   return 0;
+}
diff --git a/deps/libretro-common/samples/compat/fnmatch/Makefile b/deps/libretro-common/samples/compat/fnmatch/Makefile
new file mode 100644 (file)
index 0000000..66d741a
--- /dev/null
@@ -0,0 +1,24 @@
+TARGET := compat_fnmatch_test
+
+LIBRETRO_COMM_DIR := ../../..
+
+SOURCES := \
+       compat_fnmatch_test.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_fnmatch.c
+
+OBJS := $(SOURCES:.c=.o)
+
+CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/compat/fnmatch/compat_fnmatch_test.c b/deps/libretro-common/samples/compat/fnmatch/compat_fnmatch_test.c
new file mode 100644 (file)
index 0000000..42c3366
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_fnmatch_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <assert.h>
+#include <stddef.h>
+
+#include <compat/fnmatch.h>
+
+int main(void)
+{
+   assert(rl_fnmatch("TEST", "TEST", 0) == 0);
+   assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
+   assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
+   assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0);
+   assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0);
+   assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0);
+   assert(rl_fnmatch("TEST*", "TEST", 0) == 0);
+   assert(rl_fnmatch("TEST**", "TEST", 0) == 0);
+   assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0);
+   assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0);
+   assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0);
+   assert(rl_fnmatch("TE**ST", "TEST", 0) == 0);
+   assert(rl_fnmatch("TE**ST", "TExST", 0) == 0);
+   assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0);
+   assert(rl_fnmatch("*.*", "test.jpg", 0) == 0);
+   assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0);
+   assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0);
+   assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0);
+   assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH);
+   assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH);
+}
diff --git a/deps/libretro-common/samples/compat/snprintf/Makefile b/deps/libretro-common/samples/compat/snprintf/Makefile
new file mode 100644 (file)
index 0000000..9a8294a
--- /dev/null
@@ -0,0 +1,25 @@
+TARGET := snprintf
+
+CORE_DIR          := .
+LIBRETRO_COMM_DIR := ../../..
+
+SOURCES_C :=   \
+       $(CORE_DIR)/snprintf_test.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c
+
+OBJS := $(SOURCES_C:.c=.o)
+
+CFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/compat/snprintf/snprintf_test.c b/deps/libretro-common/samples/compat/snprintf/snprintf_test.c
new file mode 100644 (file)
index 0000000..f8558c3
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (snprintf_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <compat/strl.h>
+
+int main(int argc, char *argv[])
+{
+   char s[128];
+   char *variable      = "test1";
+   char *variable2     = "test2";
+   char *variable3     = "test3";
+   char *variable4     = "test4";
+   char *variable5     = "test5";
+   char *variable6     = "test6";
+   int ret             = snprintf(s,
+         sizeof(s), "%s%s%s%s%s%s%s%s%s%s%s", variable,
+         " : ", variable2,
+         " : ", variable3,
+         " : ", variable4,
+         " : ", variable5,
+         " : ", variable6
+         );
+
+   fprintf(stderr, "[%d], %s\n", ret, s);
+
+   return 0;
+}
diff --git a/deps/libretro-common/samples/compat/strl/Makefile b/deps/libretro-common/samples/compat/strl/Makefile
new file mode 100644 (file)
index 0000000..7b4c59f
--- /dev/null
@@ -0,0 +1,25 @@
+TARGET := strl
+
+CORE_DIR          := .
+LIBRETRO_COMM_DIR := ../../..
+
+SOURCES_C :=   \
+       $(CORE_DIR)/strl_test.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strl.c
+
+OBJS := $(SOURCES_C:.c=.o)
+
+CFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/compat/strl/strl_test.c b/deps/libretro-common/samples/compat/strl/strl_test.c
new file mode 100644 (file)
index 0000000..72ef532
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (strl_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <compat/strl.h>
+
+int main(int argc, char *argv[])
+{
+   char s[128];
+   char *variable      = "test1";
+   char *variable2     = "test2";
+   char *variable3     = "test3";
+   char *variable4     = "test4";
+   char *variable5     = "test5";
+   char *variable6     = "test6";
+   int ret             = strlcpy(s, variable, sizeof(s));
+   ret                 = strlcat(s, " : ",    sizeof(s));
+   ret                 = strlcat(s, variable2,sizeof(s));
+   ret                 = strlcat(s, " : ",    sizeof(s));
+   ret                 = strlcat(s, variable3,sizeof(s));
+   ret                 = strlcat(s, " : ",    sizeof(s));
+   ret                 = strlcat(s, variable4,sizeof(s));
+   ret                 = strlcat(s, " : ",    sizeof(s));
+   ret                 = strlcat(s, variable5,sizeof(s));
+   ret                 = strlcat(s, " : ",    sizeof(s));
+   ret                 = strlcat(s, variable6,sizeof(s));
+
+   fprintf(stderr, "[%d], %s\n", ret, s);
+
+   return 0;
+}
diff --git a/deps/libretro-common/samples/core_options/README.md b/deps/libretro-common/samples/core_options/README.md
new file mode 100644 (file)
index 0000000..7406f30
--- /dev/null
@@ -0,0 +1,59 @@
+## Adding 'enhanced' core options to a core
+
+The basic steps for updating a core to support core options v1 are as follows:
+
+- Copy `example_default/libretro_core_options.h` to the same directory as `libretro.c/.cpp`
+
+- Copy `example_default/libretro_core_options_intl.h` to the same directory as `libretro.c/.cpp`
+
+- Add `#include "libretro_core_options.h"` to `libretro.c/.cpp`
+
+- Replace any existing calls of `RETRO_ENVIRONMENT_SET_VARIABLES` with `libretro_set_core_options(retro_environment_t environ_cb)`  
+  (Note: `libretro_set_core_options()` should be called as early as possible - preferably in `retro_set_environment()`  
+  and no later than `retro_load_game()`)
+
+- Open `libretro_core_options.h` and replace the contents of the existing `option_defs_us` struct array with all required core option parameters.  
+
+## Adding core option translations
+
+To add a translation, simply:
+
+- Copy the contents of `option_defs_us` *from* `libretro_core_options.h` *to* `libretro_core_options_intl.h` into a new struct array with the appropriate language suffix
+
+- Translate all human-readable strings
+
+- Add the new struct array to the appropriate location in the `option_defs_intl` array inside `libretro_core_options.h`
+
+This is most easily understood by considering the example in `example_translation/`. Here a French translation has been added (`option_defs_fr`), with comments explaining the appropriate formatting requirements.
+
+NOTE: Since translations involve the use of UTF-8 characters, `libretro_core_options_intl.h` must include a BOM marker. *This renders translations incompatible with c89 builds*. When performing a c89 build, the flag `HAVE_NO_LANGEXTRA` *must* be defined (e.g. `-DHAVE_NO_LANGEXTRA`). This will disable all translations.
+
+## Disabling core options on unsupported frontends
+
+Sometimes it is desirable to only show a particular core option if the frontend supports the new core options v1 API. For example:
+
+- The API v1 allows cores to hide options dynamically
+
+- We can therefore create a specific 'toggle display' option to hide or show a number of other options (e.g. advanced settings)
+
+- On frontends that do not support API v1, this 'toggle display' option will have no function - it should therefore be omitted
+
+This can be handled easily by editing the `libretro_set_core_options()` function to ignore certain core name (key) values when generating option variable arrays for old-style frontends. Again, this is most easily understood by considering the example in `example_hide_option/libretro_core_options.h`:
+
+- Here, a `mycore_show_speedhacks` option is added to `option_defs_us`
+
+- On line 227, the following comparison allows the option to be skipped:  
+  (Note that another `strcmp()` may be added for each option to be omitted)
+
+```c
+if (strcmp(key, "mycore_show_speedhacks") == 0)
+       continue;
+```
+
+For any cores that require this functionality, `example_hide_option/libretro_core_options.h` should be used as a template in place of `example_default/libretro_core_options.h`
+
+## Adding core option categories
+
+Core options v2 adds a mechanism for assigning categories to options. On supported fontends, options of a particular category will be displayed in a submenu/subsection of the main core options menu. This functionality may be used to reduce visual clutter, or to effectively 'hide' advanced settings without requiring a dedicated 'toggle display' option.
+
+A template for enabling categories via the core options v2 interface is provided in `example_categories`. The usage of this code is identical to that described in the `Adding 'enhanced' core options to a core` section, with one addition: the `libretro_set_core_options()` function here includes an additional argument identifying whether the frontend has option category support (a core may wish to selectively hide or reorganise options based upon this variable).
diff --git a/deps/libretro-common/samples/core_options/example_categories/conversion_scripts/core_option_regex.py b/deps/libretro-common/samples/core_options/example_categories/conversion_scripts/core_option_regex.py
new file mode 100644 (file)
index 0000000..93916da
--- /dev/null
@@ -0,0 +1,80 @@
+import re
+
+# 0: full struct; 1: up to & including first []; 2: content between first {}
+p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*'
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
+                      r'=\s*'  # =
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
+                      r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};')  # captures full struct, it's beginning and it's content
+# 0: type name[]; 1: type; 2: name
+p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*'
+                         r'(option_cats[a-z_]{0,8}|option_defs([a-z_]{0,8}))\s*\[]')
+# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
+p_option = re.compile(r'{\s*'  # opening braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(\".*?\"|'  # key start; group 1
+                      r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|'
+                      r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|'
+                      r'[a-zA-Z0-9_]+\s*\".*?\")\s*'  # key end
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(\".*?\")\s*'  # description; group 2
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'((?:'  # group 3
+                      r'(?:NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r')+)'
+                      r'(?:'  # defs only start
+                      r'{\s*'  # opening braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'((?:'  # key/value pairs start; group 4
+                      r'{\s*'  # opening braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(?:NULL|\".*?\")\s*'  # option key
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(?:NULL|\".*?\")\s*'  # option value
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'}\s*'  # closing braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r')*)'  # key/value pairs end
+                      r'}\s*'  # closing braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(?:'  # defaults start
+                      r'(?:NULL|\".*?\")\s*'  # default value
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r')*'  # defaults end
+                      r')?'  # defs only end
+                      r'},')  # closing braces
+# analyse option group 3
+p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
+                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                    r',\s*'  # comma
+                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*')
+# analyse option group 4
+p_key_value = re.compile(r'{\s*'  # opening braces
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r'(NULL|\".*?\")\s*'  # option key; 1
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r',\s*'  # comma
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r'(NULL|\".*?\")\s*'  # option value; 2
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r'}\s*'  # closing braces
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r',?\s*'  # comma
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*')
+
+p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")')
diff --git a/deps/libretro-common/samples/core_options/example_categories/conversion_scripts/v1_to_v2_converter.py b/deps/libretro-common/samples/core_options/example_categories/conversion_scripts/v1_to_v2_converter.py
new file mode 100644 (file)
index 0000000..c32f760
--- /dev/null
@@ -0,0 +1,419 @@
+#!/usr/bin/env python3
+
+"""Core options v1 to v2 converter
+
+Just copy 'libretro_core_options.h' & 'libretro_core_options_intl.h' into the same folder as this script
+and run it! The original files will be preserved as *.v1
+"""
+import core_option_regex as cor
+import os
+import sys
+
+if os.name == 'nt':
+    joiner = '\\'
+else:
+    joiner = '/'
+dir_path = os.path.dirname(os.path.realpath(__file__))
+h_filename = joiner.join((dir_path, 'libretro_core_options.h'))
+intl_filename = joiner.join((dir_path, 'libretro_core_options_intl.h'))
+
+
+def create_v2_code_file(struct_text, file_name):
+    def replace_option(option_match):
+        _offset = option_match.start(0)
+
+        if option_match.group(3):
+            res = option_match.group(0)[:option_match.end(2) - _offset] + ',\n      NULL' + \
+                  option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \
+                  'NULL,\n      NULL,\n      ' + option_match.group(0)[option_match.end(3) - _offset:]
+        else:
+            return option_match.group(0)
+
+        return res
+
+    comment_v1 = '/*\n' \
+                 ' ********************************\n' \
+                 ' * VERSION: 1.3\n' \
+                 ' ********************************\n' \
+                 ' *\n' \
+                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
+                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
+                 ' *          fix for MSVC 2010-2013\n' \
+                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
+                 ' *          on platforms/compilers without BOM support\n' \
+                 ' * - 1.2: Use core options v1 interface when\n' \
+                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
+                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
+                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
+                 ' *        arrays containing options with a single value\n' \
+                 ' * - 1.0: First commit\n' \
+                 '*/\n'
+
+    comment_v2 = '/*\n' \
+                 ' ********************************\n' \
+                 ' * VERSION: 2.0\n' \
+                 ' ********************************\n' \
+                 ' *\n' \
+                 ' * - 2.0: Add support for core options v2 interface\n' \
+                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
+                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
+                 ' *          fix for MSVC 2010-2013\n' \
+                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
+                 ' *          on platforms/compilers without BOM support\n' \
+                 ' * - 1.2: Use core options v1 interface when\n' \
+                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
+                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
+                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
+                 ' *        arrays containing options with a single value\n' \
+                 ' * - 1.0: First commit\n' \
+                 '*/\n'
+
+    p_intl = cor.re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {'
+                            r'((?:.|[\r\n])*?)};')
+    p_set = cor.re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)'
+                           r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif')
+    new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\n' \
+              '      bool *categories_supported)\n' \
+              '{\n' \
+              '   unsigned version  = 0;\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '   unsigned language = 0;\n' \
+              '#endif\n' \
+              '\n' \
+              '   if (!environ_cb || !categories_supported)\n' \
+              '      return;\n' \
+              '\n' \
+              '   *categories_supported = false;\n' \
+              '\n' \
+              '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))\n' \
+              '      version = 0;\n' \
+              '\n' \
+              '   if (version >= 2)\n' \
+              '   {\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '      struct retro_core_options_v2_intl core_options_intl;\n' \
+              '\n' \
+              '      core_options_intl.us    = &options_us;\n' \
+              '      core_options_intl.local = NULL;\n' \
+              '\n' \
+              '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
+              '          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))\n' \
+              '         core_options_intl.local = options_intl[language];\n' \
+              '\n' \
+              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n' \
+              '            &core_options_intl);\n' \
+              '#else\n' \
+              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n' \
+              '            &options_us);\n' \
+              '#endif\n' \
+              '   }\n' \
+              '   else\n' \
+              '   {\n' \
+              '      size_t i, j;\n' \
+              '      size_t option_index              = 0;\n' \
+              '      size_t num_options               = 0;\n' \
+              '      struct retro_core_option_definition\n' \
+              '            *option_v1_defs_us         = NULL;\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '      size_t num_options_intl          = 0;\n' \
+              '      struct retro_core_option_v2_definition\n' \
+              '            *option_defs_intl          = NULL;\n' \
+              '      struct retro_core_option_definition\n' \
+              '            *option_v1_defs_intl       = NULL;\n' \
+              '      struct retro_core_options_intl\n' \
+              '            core_options_v1_intl;\n' \
+              '#endif\n' \
+              '      struct retro_variable *variables = NULL;\n' \
+              '      char **values_buf                = NULL;\n' \
+              '\n' \
+              '      /* Determine total number of options */\n' \
+              '      while (true)\n' \
+              '      {\n' \
+              '         if (option_defs_us[num_options].key)\n' \
+              '            num_options++;\n' \
+              '         else\n' \
+              '            break;\n' \
+              '      }\n' \
+              '\n' \
+              '      if (version >= 1)\n' \
+              '      {\n' \
+              '         /* Allocate US array */\n' \
+              '         option_v1_defs_us = (struct retro_core_option_definition *)\n' \
+              '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\n' \
+              '\n' \
+              '         /* Copy parameters from option_defs_us array */\n' \
+              '         for (i = 0; i < num_options; i++)\n' \
+              '         {\n' \
+              '            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];\n' \
+              '            struct retro_core_option_value *option_values         = option_def_us->values;\n' \
+              '            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];\n' \
+              '            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;\n' \
+              '\n' \
+              '            option_v1_def_us->key           = option_def_us->key;\n' \
+              '            option_v1_def_us->desc          = option_def_us->desc;\n' \
+              '            option_v1_def_us->info          = option_def_us->info;\n' \
+              '            option_v1_def_us->default_value = option_def_us->default_value;\n' \
+              '\n' \
+              '            /* Values must be copied individually... */\n' \
+              '            while (option_values->value)\n' \
+              '            {\n' \
+              '               option_v1_values->value = option_values->value;\n' \
+              '               option_v1_values->label = option_values->label;\n' \
+              '\n' \
+              '               option_values++;\n' \
+              '               option_v1_values++;\n' \
+              '            }\n' \
+              '         }\n' \
+              '\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
+              '             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&\n' \
+              '             options_intl[language])\n' \
+              '            option_defs_intl = options_intl[language]->definitions;\n' \
+              '\n' \
+              '         if (option_defs_intl)\n' \
+              '         {\n' \
+              '            /* Determine number of intl options */\n' \
+              '            while (true)\n' \
+              '            {\n' \
+              '               if (option_defs_intl[num_options_intl].key)\n' \
+              '                  num_options_intl++;\n' \
+              '               else\n' \
+              '                  break;\n' \
+              '            }\n' \
+              '\n' \
+              '            /* Allocate intl array */\n' \
+              '            option_v1_defs_intl = (struct retro_core_option_definition *)\n' \
+              '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\n' \
+              '\n' \
+              '            /* Copy parameters from option_defs_intl array */\n' \
+              '            for (i = 0; i < num_options_intl; i++)\n' \
+              '            {\n' \
+              '               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];\n' \
+              '               struct retro_core_option_value *option_values           = option_def_intl->values;\n' \
+              '               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];\n' \
+              '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;\n' \
+              '\n' \
+              '               option_v1_def_intl->key           = option_def_intl->key;\n' \
+              '               option_v1_def_intl->desc          = option_def_intl->desc;\n' \
+              '               option_v1_def_intl->info          = option_def_intl->info;\n' \
+              '               option_v1_def_intl->default_value = option_def_intl->default_value;\n' \
+              '\n' \
+              '               /* Values must be copied individually... */\n' \
+              '               while (option_values->value)\n' \
+              '               {\n' \
+              '                  option_v1_values->value = option_values->value;\n' \
+              '                  option_v1_values->label = option_values->label;\n' \
+              '\n' \
+              '                  option_values++;\n' \
+              '                  option_v1_values++;\n' \
+              '               }\n' \
+              '            }\n' \
+              '         }\n' \
+              '\n' \
+              '         core_options_v1_intl.us    = option_v1_defs_us;\n' \
+              '         core_options_v1_intl.local = option_v1_defs_intl;\n' \
+              '\n' \
+              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);\n' \
+              '#else\n' \
+              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\n' \
+              '#endif\n' \
+              '      }\n' \
+              '      else\n' \
+              '      {\n' \
+              '         /* Allocate arrays */\n' \
+              '         variables  = (struct retro_variable *)calloc(num_options + 1,\n' \
+              '               sizeof(struct retro_variable));\n' \
+              '         values_buf = (char **)calloc(num_options, sizeof(char *));\n' \
+              '\n' \
+              '         if (!variables || !values_buf)\n' \
+              '            goto error;\n' \
+              '\n' \
+              '         /* Copy parameters from option_defs_us array */\n' \
+              '         for (i = 0; i < num_options; i++)\n' \
+              '         {\n' \
+              '            const char *key                        = option_defs_us[i].key;\n' \
+              '            const char *desc                       = option_defs_us[i].desc;\n' \
+              '            const char *default_value              = option_defs_us[i].default_value;\n' \
+              '            struct retro_core_option_value *values = option_defs_us[i].values;\n' \
+              '            size_t buf_len                         = 3;\n' \
+              '            size_t default_index                   = 0;\n' \
+              '\n' \
+              '            values_buf[i] = NULL;\n' \
+              '\n' \
+              '            if (desc)\n' \
+              '            {\n' \
+              '               size_t num_values = 0;\n' \
+              '\n' \
+              '               /* Determine number of values */\n' \
+              '               while (true)\n' \
+              '               {\n' \
+              '                  if (values[num_values].value)\n' \
+              '                  {\n' \
+              '                     /* Check if this is the default value */\n' \
+              '                     if (default_value)\n' \
+              '                        if (strcmp(values[num_values].value, default_value) == 0)\n' \
+              '                           default_index = num_values;\n' \
+              '\n' \
+              '                     buf_len += strlen(values[num_values].value);\n' \
+              '                     num_values++;\n' \
+              '                  }\n' \
+              '                  else\n' \
+              '                     break;\n' \
+              '               }\n' \
+              '\n' \
+              '               /* Build values string */\n' \
+              '               if (num_values > 0)\n' \
+              '               {\n' \
+              '                  buf_len += num_values - 1;\n' \
+              '                  buf_len += strlen(desc);\n' \
+              '\n' \
+              '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\n' \
+              '                  if (!values_buf[i])\n' \
+              '                     goto error;\n' \
+              '\n' \
+              '                  strcpy(values_buf[i], desc);\n' \
+              '                  strcat(values_buf[i], "; ");\n' \
+              '\n' \
+              '                  /* Default value goes first */\n' \
+              '                  strcat(values_buf[i], values[default_index].value);\n' \
+              '\n' \
+              '                  /* Add remaining values */\n' \
+              '                  for (j = 0; j < num_values; j++)\n' \
+              '                  {\n' \
+              '                     if (j != default_index)\n' \
+              '                     {\n' \
+              '                        strcat(values_buf[i], "|");\n' \
+              '                        strcat(values_buf[i], values[j].value);\n' \
+              '                     }\n' \
+              '                  }\n' \
+              '               }\n' \
+              '            }\n' \
+              '\n' \
+              '            variables[option_index].key   = key;\n' \
+              '            variables[option_index].value = values_buf[i];\n' \
+              '            option_index++;\n' \
+              '         }\n' \
+              '\n' \
+              '         /* Set variables */\n' \
+              '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n' \
+              '      }\n' \
+              '\n' \
+              'error:\n' \
+              '      /* Clean up */\n' \
+              '\n' \
+              '      if (option_v1_defs_us)\n' \
+              '      {\n' \
+              '         free(option_v1_defs_us);\n' \
+              '         option_v1_defs_us = NULL;\n' \
+              '      }\n' \
+              '\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '      if (option_v1_defs_intl)\n' \
+              '      {\n' \
+              '         free(option_v1_defs_intl);\n' \
+              '         option_v1_defs_intl = NULL;\n' \
+              '      }\n' \
+              '#endif\n' \
+              '\n' \
+              '      if (values_buf)\n' \
+              '      {\n' \
+              '         for (i = 0; i < num_options; i++)\n' \
+              '         {\n' \
+              '            if (values_buf[i])\n' \
+              '            {\n' \
+              '               free(values_buf[i]);\n' \
+              '               values_buf[i] = NULL;\n' \
+              '            }\n' \
+              '         }\n' \
+              '\n' \
+              '         free(values_buf);\n' \
+              '         values_buf = NULL;\n' \
+              '      }\n' \
+              '\n' \
+              '      if (variables)\n' \
+              '      {\n' \
+              '         free(variables);\n' \
+              '         variables = NULL;\n' \
+              '      }\n' \
+              '   }\n' \
+              '}\n' \
+              '\n' \
+              '#ifdef __cplusplus\n' \
+              '}\n' \
+              '#endif'
+
+    struct_groups = cor.p_struct.finditer(struct_text)
+    out_text = struct_text
+
+    for construct in struct_groups:
+        repl_text = ''
+        declaration = construct.group(1)
+        struct_match = cor.p_type_name.search(declaration)
+        if struct_match:
+            struct_type_name = struct_match.group(1, 2)
+        else:
+            return -1
+
+        if 'retro_core_option_definition' == struct_type_name[0]:
+            import shutil
+            shutil.copy(file_name, file_name + '.v1')
+            new_declaration = f'\nstruct retro_core_option_v2_category option_cats_{struct_match.group(3)}[] = ' \
+                              '{\n   { NULL, NULL, NULL },\n' \
+                              '};\n\n' \
+                              + declaration[:struct_match.start(1)] + \
+                              'retro_core_option_v2_definition' \
+                              + declaration[struct_match.end(1):]
+            offset = construct.start(0)
+            repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,
+                                               construct.group(0)[:construct.start(2) - offset])
+            content = construct.group(2)
+            new_content = cor.p_option.sub(replace_option, content)
+
+            repl_text = repl_text + new_content + cor.re.sub(r'{\s*NULL,\s*NULL,\s*NULL,\s*{\{0}},\s*NULL\s*},\s*};',
+                                                             '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};'
+                                                             '\n\nstruct retro_core_options_v2 options_' +
+                                                             struct_match.group(3) + ' = {\n'
+                                                             f'   option_cats_{struct_match.group(3)},\n'
+                                                             f'   option_defs_{struct_match.group(3)}\n'
+                                                             '};',
+                                                             construct.group(0)[construct.end(2) - offset:])
+            out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text)
+        else:
+            return -2
+    with open(file_name, 'w', encoding='utf-8') as code_file:
+        out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)
+        intl = p_intl.search(out_text)
+        if intl:
+            new_intl = out_text[:intl.start(1)] \
+                       + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \
+                       + out_text[intl.end(1):intl.start(2)] + cor.re.sub(r'option_defs_', '&options_', intl.group(2)) \
+                       + out_text[intl.end(2):]
+            out_text = p_set.sub(new_set, new_intl)
+        else:
+            out_text = p_set.sub(new_set, out_text)
+        code_file.write(out_text)
+
+    return 1
+
+
+# --------------------          MAIN          -------------------- #
+
+if __name__ == '__main__':
+    try:
+        for file in (h_filename, intl_filename):
+            if os.path.isfile(file):
+                with open(file, 'r+', encoding='utf-8') as h_file:
+                    text = h_file.read()
+                    test = create_v2_code_file(text, file)
+                    if -1 > test:
+                        print('Your file looks like it already is v2? (' + file + ')')
+                        continue
+                    if 0 > test:
+                        print('An error occured! Please make sure to use the complete v1 struct! (' + file + ')')
+                        continue
+            else:
+                print(file + ' not found.')
+    except EnvironmentError:
+        print('Something went wrong with reading or writing files!')
+        sys.exit(1)
diff --git a/deps/libretro-common/samples/core_options/example_categories/libretro_core_options.h b/deps/libretro-common/samples/core_options/example_categories/libretro_core_options.h
new file mode 100644 (file)
index 0000000..4179c4b
--- /dev/null
@@ -0,0 +1,458 @@
+#ifndef LIBRETRO_CORE_OPTIONS_H__
+#define LIBRETRO_CORE_OPTIONS_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libretro.h>
+#include <retro_inline.h>
+
+#ifndef HAVE_NO_LANGEXTRA
+#include "libretro_core_options_intl.h"
+#endif
+
+/*
+ ********************************
+ * VERSION: 2.0
+ ********************************
+ *
+ * - 2.0: Add support for core options v2 interface
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_ENGLISH */
+
+/* Default language:
+ * - All other languages must include the same keys and values
+ * - Will be used as a fallback in the event that frontend language
+ *   is not available
+ * - Will be used as a fallback for any missing entries in
+ *   frontend language definition */
+
+struct retro_core_option_v2_category option_cats_us[] = {
+   {
+      "video",                     /* key (category name) */
+      "Video",                     /* category description (label) */
+      "Configure display options." /* category sublabel */
+   },
+   {
+      "hacks",
+      "Advanced",
+      "Options affecting low-level emulation performance and accuracy."
+   },
+   { NULL, NULL, NULL },
+};
+
+struct retro_core_option_v2_definition option_defs_us[] = {
+   {
+      "mycore_region",                            /* key (option name) */
+      "Console Region",                           /* description (label) */
+      NULL,                                       /* 'categorised' description (used instead of
+                                                   * 'description' if frontend has category
+                                                   * support; if NULL or empty, regular
+                                                   * description is always used */
+      "Specify which region the system is from.", /* sublabel */
+      NULL,                                       /* 'categorised' sublabel (used instead of
+                                                   * 'sublabel' if frontend has category
+                                                   * support; if NULL or empty, regular
+                                                   * sublabel is always used */
+      NULL,                                       /* category key (must match an entry in
+                                                   * option_cats_us; if NULL or empty,
+                                                   * option is uncategorised */
+      {
+         { "auto",   "Auto" },                    /* value_1, value_1_label */
+         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
+         { "ntsc-u", "America" },                 /* value_3, value_3_label */
+         { "pal",    "Europe" },                  /* value_4, value_4_label */
+         { NULL, NULL },
+      },
+      "auto"                                      /* default_value */
+   },
+   {
+      "mycore_video_scale",
+      "Video > Scale",   /* description: here a 'Video >' prefix is used to
+                          * signify a category on frontends without explicit
+                          * category support */
+      "Scale",           /* 'categorised' description: will be displayed inside
+                          * the 'Video' submenu */
+      "Set internal video scale factor.",
+      NULL,
+      "video",           /* category key */
+      {
+         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
+         { "2x", NULL }, /* and can displayed directly, the value_label should */
+         { "3x", NULL }, /* be set to NULL                                     */
+         { "4x", NULL },
+         { NULL, NULL },
+      },
+      "3x"
+   },
+   {
+      "mycore_overclock",
+      "Advanced > Reduce Slowdown",
+      "Reduce Slowdown",
+      "Enabling 'Advanced > Reduce Slowdown' will reduce accuracy.", /* sublabel */
+      "Enabling 'Reduce Slowdown' will reduce accuracy.",            /* 'categorised' sublabel:
+                               * will be displayed inside the 'Advanced' submenu; note that
+                               * 'Advanced > Reduce Slowdown' is replaced with 'Reduce Slowdown' */
+      "hacks",
+      {
+         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
+         { "disabled", NULL }, /* value_label should be set to NULL             */
+         { NULL, NULL },
+      },
+      "disabled"
+   },
+   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
+};
+
+struct retro_core_options_v2 options_us = {
+   option_cats_us,
+   option_defs_us
+};
+
+/*
+ ********************************
+ * Language Mapping
+ ********************************
+*/
+
+#ifndef HAVE_NO_LANGEXTRA
+struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {
+   &options_us, /* RETRO_LANGUAGE_ENGLISH */
+   NULL,        /* RETRO_LANGUAGE_JAPANESE */
+   &options_fr, /* RETRO_LANGUAGE_FRENCH */
+   NULL,        /* RETRO_LANGUAGE_SPANISH */
+   NULL,        /* RETRO_LANGUAGE_GERMAN */
+   NULL,        /* RETRO_LANGUAGE_ITALIAN */
+   NULL,        /* RETRO_LANGUAGE_DUTCH */
+   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+   NULL,        /* RETRO_LANGUAGE_RUSSIAN */
+   NULL,        /* RETRO_LANGUAGE_KOREAN */
+   NULL,        /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+   NULL,        /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+   NULL,        /* RETRO_LANGUAGE_ESPERANTO */
+   NULL,        /* RETRO_LANGUAGE_POLISH */
+   NULL,        /* RETRO_LANGUAGE_VIETNAMESE */
+   NULL,        /* RETRO_LANGUAGE_ARABIC */
+   NULL,        /* RETRO_LANGUAGE_GREEK */
+   NULL,        /* RETRO_LANGUAGE_TURKISH */
+   NULL,        /* RETRO_LANGUAGE_SLOVAK */
+   NULL,        /* RETRO_LANGUAGE_PERSIAN */
+   NULL,        /* RETRO_LANGUAGE_HEBREW */
+   NULL,        /* RETRO_LANGUAGE_ASTURIAN */
+   NULL,        /* RETRO_LANGUAGE_FINNISH */
+   NULL,        /* RETRO_LANGUAGE_INDONESIAN */
+   NULL,        /* RETRO_LANGUAGE_SWEDISH */
+   NULL,        /* RETRO_LANGUAGE_UKRAINIAN */
+   NULL,        /* RETRO_LANGUAGE_CZECH */
+};
+#endif
+
+/*
+ ********************************
+ * Functions
+ ********************************
+*/
+
+/* Handles configuration/setting of core options.
+ * Should be called as early as possible - ideally inside
+ * retro_set_environment(), and no later than retro_load_game()
+ * > We place the function body in the header to avoid the
+ *   necessity of adding more .c files (i.e. want this to
+ *   be as painless as possible for core devs)
+ */
+
+static INLINE void libretro_set_core_options(retro_environment_t environ_cb,
+      bool *categories_supported)
+{
+   unsigned version  = 0;
+#ifndef HAVE_NO_LANGEXTRA
+   unsigned language = 0;
+#endif
+
+   if (!environ_cb || !categories_supported)
+      return;
+
+   *categories_supported = false;
+
+   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))
+      version = 0;
+
+   if (version >= 2)
+   {
+#ifndef HAVE_NO_LANGEXTRA
+      struct retro_core_options_v2_intl core_options_intl;
+
+      core_options_intl.us    = &options_us;
+      core_options_intl.local = NULL;
+
+      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
+          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
+         core_options_intl.local = options_intl[language];
+
+      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,
+            &core_options_intl);
+#else
+      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,
+            &options_us);
+#endif
+   }
+   else
+   {
+      size_t i, j;
+      size_t option_index              = 0;
+      size_t num_options               = 0;
+      struct retro_core_option_definition
+            *option_v1_defs_us         = NULL;
+#ifndef HAVE_NO_LANGEXTRA
+      size_t num_options_intl          = 0;
+      struct retro_core_option_v2_definition
+            *option_defs_intl          = NULL;
+      struct retro_core_option_definition
+            *option_v1_defs_intl       = NULL;
+      struct retro_core_options_intl
+            core_options_v1_intl;
+#endif
+      struct retro_variable *variables = NULL;
+      char **values_buf                = NULL;
+
+      /* Determine total number of options */
+      while (true)
+      {
+         if (option_defs_us[num_options].key)
+            num_options++;
+         else
+            break;
+      }
+
+      if (version >= 1)
+      {
+         /* Allocate US array */
+         option_v1_defs_us = (struct retro_core_option_definition *)
+               calloc(num_options + 1, sizeof(struct retro_core_option_definition));
+
+         /* Copy parameters from option_defs_us array */
+         for (i = 0; i < num_options; i++)
+         {
+            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];
+            struct retro_core_option_value *option_values         = option_def_us->values;
+            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];
+            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;
+
+            option_v1_def_us->key           = option_def_us->key;
+            option_v1_def_us->desc          = option_def_us->desc;
+            option_v1_def_us->info          = option_def_us->info;
+            option_v1_def_us->default_value = option_def_us->default_value;
+
+            /* Values must be copied individually... */
+            while (option_values->value)
+            {
+               option_v1_values->value = option_values->value;
+               option_v1_values->label = option_values->label;
+
+               option_values++;
+               option_v1_values++;
+            }
+         }
+
+#ifndef HAVE_NO_LANGEXTRA
+         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
+             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&
+             options_intl[language])
+            option_defs_intl = options_intl[language]->definitions;
+
+         if (option_defs_intl)
+         {
+            /* Determine number of intl options */
+            while (true)
+            {
+               if (option_defs_intl[num_options_intl].key)
+                  num_options_intl++;
+               else
+                  break;
+            }
+
+            /* Allocate intl array */
+            option_v1_defs_intl = (struct retro_core_option_definition *)
+                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));
+
+            /* Copy parameters from option_defs_intl array */
+            for (i = 0; i < num_options_intl; i++)
+            {
+               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];
+               struct retro_core_option_value *option_values           = option_def_intl->values;
+               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];
+               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;
+
+               option_v1_def_intl->key           = option_def_intl->key;
+               option_v1_def_intl->desc          = option_def_intl->desc;
+               option_v1_def_intl->info          = option_def_intl->info;
+               option_v1_def_intl->default_value = option_def_intl->default_value;
+
+               /* Values must be copied individually... */
+               while (option_values->value)
+               {
+                  option_v1_values->value = option_values->value;
+                  option_v1_values->label = option_values->label;
+
+                  option_values++;
+                  option_v1_values++;
+               }
+            }
+         }
+
+         core_options_v1_intl.us    = option_v1_defs_us;
+         core_options_v1_intl.local = option_v1_defs_intl;
+
+         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);
+#else
+         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);
+#endif
+      }
+      else
+      {
+         /* Allocate arrays */
+         variables  = (struct retro_variable *)calloc(num_options + 1,
+               sizeof(struct retro_variable));
+         values_buf = (char **)calloc(num_options, sizeof(char *));
+
+         if (!variables || !values_buf)
+            goto error;
+
+         /* Copy parameters from option_defs_us array */
+         for (i = 0; i < num_options; i++)
+         {
+            const char *key                        = option_defs_us[i].key;
+            const char *desc                       = option_defs_us[i].desc;
+            const char *default_value              = option_defs_us[i].default_value;
+            struct retro_core_option_value *values = option_defs_us[i].values;
+            size_t buf_len                         = 3;
+            size_t default_index                   = 0;
+
+            values_buf[i] = NULL;
+
+            if (desc)
+            {
+               size_t num_values = 0;
+
+               /* Determine number of values */
+               while (true)
+               {
+                  if (values[num_values].value)
+                  {
+                     /* Check if this is the default value */
+                     if (default_value)
+                        if (strcmp(values[num_values].value, default_value) == 0)
+                           default_index = num_values;
+
+                     buf_len += strlen(values[num_values].value);
+                     num_values++;
+                  }
+                  else
+                     break;
+               }
+
+               /* Build values string */
+               if (num_values > 0)
+               {
+                  buf_len += num_values - 1;
+                  buf_len += strlen(desc);
+
+                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));
+                  if (!values_buf[i])
+                     goto error;
+
+                  strcpy(values_buf[i], desc);
+                  strcat(values_buf[i], "; ");
+
+                  /* Default value goes first */
+                  strcat(values_buf[i], values[default_index].value);
+
+                  /* Add remaining values */
+                  for (j = 0; j < num_values; j++)
+                  {
+                     if (j != default_index)
+                     {
+                        strcat(values_buf[i], "|");
+                        strcat(values_buf[i], values[j].value);
+                     }
+                  }
+               }
+            }
+
+            variables[option_index].key   = key;
+            variables[option_index].value = values_buf[i];
+            option_index++;
+         }
+
+         /* Set variables */
+         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
+      }
+
+error:
+      /* Clean up */
+
+      if (option_v1_defs_us)
+      {
+         free(option_v1_defs_us);
+         option_v1_defs_us = NULL;
+      }
+
+#ifndef HAVE_NO_LANGEXTRA
+      if (option_v1_defs_intl)
+      {
+         free(option_v1_defs_intl);
+         option_v1_defs_intl = NULL;
+      }
+#endif
+
+      if (values_buf)
+      {
+         for (i = 0; i < num_options; i++)
+         {
+            if (values_buf[i])
+            {
+               free(values_buf[i]);
+               values_buf[i] = NULL;
+            }
+         }
+
+         free(values_buf);
+         values_buf = NULL;
+      }
+
+      if (variables)
+      {
+         free(variables);
+         variables = NULL;
+      }
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_categories/libretro_core_options_intl.h b/deps/libretro-common/samples/core_options/example_categories/libretro_core_options_intl.h
new file mode 100644 (file)
index 0000000..0eaf762
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
+#define LIBRETRO_CORE_OPTIONS_INTL_H__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
+/* https://support.microsoft.com/en-us/kb/980263 */
+#pragma execution_character_set("utf-8")
+#pragma warning(disable:4566)
+#endif
+
+#include <libretro.h>
+
+/*
+ ********************************
+ * VERSION: 2.0
+ ********************************
+ *
+ * - 2.0: Add support for core options v2 interface
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_JAPANESE */
+
+/* RETRO_LANGUAGE_FRENCH */
+
+struct retro_core_option_v2_category option_cats_fr[] = {
+   {
+      "video",                              /* key must match option_cats_us entry */
+      "Vidéo",                              /* translated category description */
+      "Configurez les options d'affichage." /* translated category sublabel */
+   },
+   {
+      "hacks",
+      "Avancée",
+      "Options affectant les performances et la précision de l'émulation de bas niveau."
+   },
+   { NULL, NULL, NULL },
+};
+
+struct retro_core_option_v2_definition option_defs_fr[] = {
+   {
+      "mycore_region",                             /* key must match option_defs_us entry */
+      "Région de la console",                      /* translated description */
+      NULL,
+      "Spécifiez la région d'origine du système.", /* translated sublabel */
+      NULL,
+      NULL,                                        /* category key is taken from option_defs_us
+                                                    * -> can set to NULL here */
+      {
+         { "auto",   "Auto" },                     /* value must match option_defs_us entry   */
+         { "ntsc-j", "Japon" },                    /* > only value_label should be translated */
+         { "ntsc-u", "Amérique" },
+         { "pal",    "L'Europe" },
+         { NULL, NULL },
+      },
+      NULL                                         /* default_value is taken from option_defs_us
+                                                    * -> can set to NULL here */
+   },
+   {
+      "mycore_video_scale",
+      "Vidéo > Échelle", /* translated description */
+      "Échelle",         /* translated 'categorised' description */
+      "Définir le facteur d'échelle vidéo interne.",
+      NULL,
+      NULL,
+      {
+         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */
+      },
+      NULL
+   },
+   {
+      "mycore_overclock",
+      "Avancé > Réduire le ralentissement",
+      "Réduire le ralentissement",
+      "L'activation de « Avancé > Réduire le ralentissement » réduira la précision.", /* translated sublabel */
+      "L'activation de « Réduire le ralentissement » réduira la précision.",          /* translated 'categorised'
+                                                                                       * sublabel */
+      NULL,
+      {
+         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */
+      },
+      NULL
+   },
+   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
+};
+
+struct retro_core_options_v2 options_fr = {
+   option_cats_fr,
+   option_defs_fr
+};
+
+/* RETRO_LANGUAGE_SPANISH */
+
+/* RETRO_LANGUAGE_GERMAN */
+
+/* RETRO_LANGUAGE_ITALIAN */
+
+/* RETRO_LANGUAGE_DUTCH */
+
+/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+
+/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+
+/* RETRO_LANGUAGE_RUSSIAN */
+
+/* RETRO_LANGUAGE_KOREAN */
+
+/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+
+/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+
+/* RETRO_LANGUAGE_ESPERANTO */
+
+/* RETRO_LANGUAGE_POLISH */
+
+/* RETRO_LANGUAGE_VIETNAMESE */
+
+/* RETRO_LANGUAGE_ARABIC */
+
+/* RETRO_LANGUAGE_GREEK */
+
+/* RETRO_LANGUAGE_TURKISH */
+
+/* RETRO_LANGUAGE_SLOVAK */
+
+/* RETRO_LANGUAGE_PERSIAN */
+
+/* RETRO_LANGUAGE_HEBREW */
+
+/* RETRO_LANGUAGE_ASTURIAN */
+
+/* RETRO_LANGUAGE_FINNISH */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_default/libretro_core_options.h b/deps/libretro-common/samples/core_options/example_default/libretro_core_options.h
new file mode 100644 (file)
index 0000000..fbb9cfc
--- /dev/null
@@ -0,0 +1,291 @@
+#ifndef LIBRETRO_CORE_OPTIONS_H__
+#define LIBRETRO_CORE_OPTIONS_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libretro.h>
+#include <retro_inline.h>
+
+#ifndef HAVE_NO_LANGEXTRA
+#include "libretro_core_options_intl.h"
+#endif
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_ENGLISH */
+
+/* Default language:
+ * - All other languages must include the same keys and values
+ * - Will be used as a fallback in the event that frontend language
+ *   is not available
+ * - Will be used as a fallback for any missing entries in
+ *   frontend language definition */
+
+struct retro_core_option_definition option_defs_us[] = {
+   {
+      "mycore_region",                            /* key (option name) */
+      "Console Region",                           /* description (label) */
+      "Specify which region the system is from.", /* sublabel */
+      {
+         { "auto",   "Auto" },                    /* value_1, value_1_label */
+         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
+         { "ntsc-u", "America" },                 /* value_3, value_3_label */
+         { "pal",    "Europe" },                  /* value_4, value_4_label */
+         { NULL, NULL },
+      },
+      "auto"                                      /* default_value */
+   },
+   {
+      "mycore_video_scale",
+      "Video Scale",
+      "Set internal video scale factor.",
+      {
+         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
+         { "2x", NULL }, /* and can displayed directly, the value_label should */
+         { "3x", NULL }, /* be set to NULL                                     */
+         { "4x", NULL },
+         { NULL, NULL },
+      },
+      "3x"
+   },
+   {
+      "mycore_overclock",
+      "Reduce Slowdown",
+      "Enable CPU overclock (unsafe).",
+      {
+         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
+         { "disabled", NULL }, /* value_label should be set to NULL             */
+         { NULL, NULL },
+      },
+      "disabled"
+   },
+   { NULL, NULL, NULL, {{0}}, NULL },
+};
+
+/*
+ ********************************
+ * Language Mapping
+ ********************************
+*/
+
+#ifndef HAVE_NO_LANGEXTRA
+struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
+   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
+   NULL,           /* RETRO_LANGUAGE_JAPANESE */
+   NULL,           /* RETRO_LANGUAGE_FRENCH */
+   NULL,           /* RETRO_LANGUAGE_SPANISH */
+   NULL,           /* RETRO_LANGUAGE_GERMAN */
+   NULL,           /* RETRO_LANGUAGE_ITALIAN */
+   NULL,           /* RETRO_LANGUAGE_DUTCH */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
+   NULL,           /* RETRO_LANGUAGE_KOREAN */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
+   NULL,           /* RETRO_LANGUAGE_POLISH */
+   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
+   NULL,           /* RETRO_LANGUAGE_ARABIC */
+   NULL,           /* RETRO_LANGUAGE_GREEK */
+   NULL,           /* RETRO_LANGUAGE_TURKISH */
+   NULL,           /* RETRO_LANGUAGE_SLOVAK */
+   NULL,           /* RETRO_LANGUAGE_PERSIAN */
+   NULL,           /* RETRO_LANGUAGE_HEBREW */
+   NULL,           /* RETRO_LANGUAGE_ASTURIAN */
+   NULL,           /* RETRO_LANGUAGE_FINNISH */
+   NULL,           /* RETRO_LANGUAGE_INDONESIAN */
+   NULL,           /* RETRO_LANGUAGE_SWEDISH */
+   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
+   NULL,           /* RETRO_LANGUAGE_CZECH */
+
+};
+#endif
+
+/*
+ ********************************
+ * Functions
+ ********************************
+*/
+
+/* Handles configuration/setting of core options.
+ * Should be called as early as possible - ideally inside
+ * retro_set_environment(), and no later than retro_load_game()
+ * > We place the function body in the header to avoid the
+ *   necessity of adding more .c files (i.e. want this to
+ *   be as painless as possible for core devs)
+ */
+
+static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
+{
+   unsigned version = 0;
+
+   if (!environ_cb)
+      return;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
+   {
+#ifndef HAVE_NO_LANGEXTRA
+      struct retro_core_options_intl core_options_intl;
+      unsigned language = 0;
+
+      core_options_intl.us    = option_defs_us;
+      core_options_intl.local = NULL;
+
+      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
+          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
+         core_options_intl.local = option_defs_intl[language];
+
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
+#else
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
+#endif
+   }
+   else
+   {
+      size_t i;
+      size_t num_options               = 0;
+      struct retro_variable *variables = NULL;
+      char **values_buf                = NULL;
+
+      /* Determine number of options */
+      for (;;)
+      {
+         if (!option_defs_us[num_options].key)
+            break;
+         num_options++;
+      }
+
+      /* Allocate arrays */
+      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
+      values_buf = (char **)calloc(num_options, sizeof(char *));
+
+      if (!variables || !values_buf)
+         goto error;
+
+      /* Copy parameters from option_defs_us array */
+      for (i = 0; i < num_options; i++)
+      {
+         const char *key                        = option_defs_us[i].key;
+         const char *desc                       = option_defs_us[i].desc;
+         const char *default_value              = option_defs_us[i].default_value;
+         struct retro_core_option_value *values = option_defs_us[i].values;
+         size_t buf_len                         = 3;
+         size_t default_index                   = 0;
+
+         values_buf[i] = NULL;
+
+         if (desc)
+         {
+            size_t num_values = 0;
+
+            /* Determine number of values */
+            for (;;)
+            {
+               if (!values[num_values].value)
+                  break;
+
+               /* Check if this is the default value */
+               if (default_value)
+                  if (strcmp(values[num_values].value, default_value) == 0)
+                     default_index = num_values;
+
+               buf_len += strlen(values[num_values].value);
+               num_values++;
+            }
+
+            /* Build values string */
+            if (num_values > 0)
+            {
+               size_t j;
+
+               buf_len += num_values - 1;
+               buf_len += strlen(desc);
+
+               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
+               if (!values_buf[i])
+                  goto error;
+
+               strcpy(values_buf[i], desc);
+               strcat(values_buf[i], "; ");
+
+               /* Default value goes first */
+               strcat(values_buf[i], values[default_index].value);
+
+               /* Add remaining values */
+               for (j = 0; j < num_values; j++)
+               {
+                  if (j != default_index)
+                  {
+                     strcat(values_buf[i], "|");
+                     strcat(values_buf[i], values[j].value);
+                  }
+               }
+            }
+         }
+
+         variables[i].key   = key;
+         variables[i].value = values_buf[i];
+      }
+
+      /* Set variables */
+      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
+
+error:
+
+      /* Clean up */
+      if (values_buf)
+      {
+         for (i = 0; i < num_options; i++)
+         {
+            if (values_buf[i])
+            {
+               free(values_buf[i]);
+               values_buf[i] = NULL;
+            }
+         }
+
+         free(values_buf);
+         values_buf = NULL;
+      }
+
+      if (variables)
+      {
+         free(variables);
+         variables = NULL;
+      }
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h b/deps/libretro-common/samples/core_options/example_default/libretro_core_options_intl.h
new file mode 100644 (file)
index 0000000..5288788
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
+#define LIBRETRO_CORE_OPTIONS_INTL_H__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
+/* https://support.microsoft.com/en-us/kb/980263 */
+#pragma execution_character_set("utf-8")
+#pragma warning(disable:4566)
+#endif
+
+#include <libretro.h>
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_JAPANESE */
+
+/* RETRO_LANGUAGE_FRENCH */
+
+/* RETRO_LANGUAGE_SPANISH */
+
+/* RETRO_LANGUAGE_GERMAN */
+
+/* RETRO_LANGUAGE_ITALIAN */
+
+/* RETRO_LANGUAGE_DUTCH */
+
+/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+
+/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+
+/* RETRO_LANGUAGE_RUSSIAN */
+
+/* RETRO_LANGUAGE_KOREAN */
+
+/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+
+/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+
+/* RETRO_LANGUAGE_ESPERANTO */
+
+/* RETRO_LANGUAGE_POLISH */
+
+/* RETRO_LANGUAGE_VIETNAMESE */
+
+/* RETRO_LANGUAGE_ARABIC */
+
+/* RETRO_LANGUAGE_GREEK */
+
+/* RETRO_LANGUAGE_TURKISH */
+
+/* RETRO_LANGUAGE_SLOVAK */
+
+/* RETRO_LANGUAGE_PERSIAN */
+
+/* RETRO_LANGUAGE_HEBREW */
+
+/* RETRO_LANGUAGE_ASTURIAN */
+
+/* RETRO_LANGUAGE_FINNISH */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h b/deps/libretro-common/samples/core_options/example_hide_option/libretro_core_options.h
new file mode 100644 (file)
index 0000000..df7afdd
--- /dev/null
@@ -0,0 +1,317 @@
+#ifndef LIBRETRO_CORE_OPTIONS_H__
+#define LIBRETRO_CORE_OPTIONS_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libretro.h>
+#include <retro_inline.h>
+
+#ifndef HAVE_NO_LANGEXTRA
+#include "libretro_core_options_intl.h"
+#endif
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_ENGLISH */
+
+/* Default language:
+ * - All other languages must include the same keys and values
+ * - Will be used as a fallback in the event that frontend language
+ *   is not available
+ * - Will be used as a fallback for any missing entries in
+ *   frontend language definition */
+
+struct retro_core_option_definition option_defs_us[] = {
+   {
+      "mycore_region",                            /* key (option name) */
+      "Console Region",                           /* description (label) */
+      "Specify which region the system is from.", /* sublabel */
+      {
+         { "auto",   "Auto" },                    /* value_1, value_1_label */
+         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
+         { "ntsc-u", "America" },                 /* value_3, value_3_label */
+         { "pal",    "Europe" },                  /* value_4, value_4_label */
+         { NULL, NULL },
+      },
+      "auto"                                      /* default_value */
+   },
+   {
+      "mycore_video_scale",
+      "Video Scale",
+      "Set internal video scale factor.",
+      {
+         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
+         { "2x", NULL }, /* and can displayed directly, the value_label should */
+         { "3x", NULL }, /* be set to NULL                                     */
+         { "4x", NULL },
+         { NULL, NULL },
+      },
+      "3x"
+   },
+   /* This 'mycore_show_speedhacks' option will only be shown
+    * if the frontend supports core options API v1.
+    * It will be hidden on older frontends.
+    * See line 227 */
+   {
+      "mycore_show_speedhacks",
+      "Show Unsafe Settings",
+      "Enable configuration of emulation speed hacks.",
+      {
+         { "enabled",  NULL },
+         { "disabled", NULL },
+         { NULL, NULL},
+      },
+      "disabled"
+   },
+   {
+      "mycore_overclock",
+      "Reduce Slowdown",
+      "Enable CPU overclock (unsafe).",
+      {
+         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
+         { "disabled", NULL }, /* value_label should be set to NULL             */
+         { NULL, NULL },
+      },
+      "disabled"
+   },
+   { NULL, NULL, NULL, {{0}}, NULL },
+};
+
+/*
+ ********************************
+ * Language Mapping
+ ********************************
+*/
+
+#ifndef HAVE_NO_LANGEXTRA
+struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
+   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
+   NULL,           /* RETRO_LANGUAGE_JAPANESE */
+   NULL,           /* RETRO_LANGUAGE_FRENCH */
+   NULL,           /* RETRO_LANGUAGE_SPANISH */
+   NULL,           /* RETRO_LANGUAGE_GERMAN */
+   NULL,           /* RETRO_LANGUAGE_ITALIAN */
+   NULL,           /* RETRO_LANGUAGE_DUTCH */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
+   NULL,           /* RETRO_LANGUAGE_KOREAN */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
+   NULL,           /* RETRO_LANGUAGE_POLISH */
+   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
+   NULL,           /* RETRO_LANGUAGE_ARABIC */
+   NULL,           /* RETRO_LANGUAGE_GREEK */
+   NULL,           /* RETRO_LANGUAGE_TURKISH */
+   NULL,           /* RETRO_LANGUAGE_SLOVAK */
+   NULL,           /* RETRO_LANGUAGE_PERSIAN */
+   NULL,           /* RETRO_LANGUAGE_HEBREW */
+   NULL,           /* RETRO_LANGUAGE_ASTURIAN */
+   NULL,           /* RETRO_LANGUAGE_FINNISH */
+   NULL,           /* RETRO_LANGUAGE_INDONESIAN */
+   NULL,           /* RETRO_LANGUAGE_SWEDISH */
+   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
+   NULL,           /* RETRO_LANGUAGE_CZECH */
+};
+#endif
+
+/*
+ ********************************
+ * Functions
+ ********************************
+*/
+
+/* Handles configuration/setting of core options.
+ * Should be called as early as possible - ideally inside
+ * retro_set_environment(), and no later than retro_load_game()
+ * > We place the function body in the header to avoid the
+ *   necessity of adding more .c files (i.e. want this to
+ *   be as painless as possible for core devs)
+ */
+
+static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
+{
+   unsigned version = 0;
+
+   if (!environ_cb)
+      return;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
+   {
+#ifndef HAVE_NO_LANGEXTRA
+      struct retro_core_options_intl core_options_intl;
+      unsigned language = 0;
+
+      core_options_intl.us    = option_defs_us;
+      core_options_intl.local = NULL;
+
+      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
+          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
+         core_options_intl.local = option_defs_intl[language];
+
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
+#else
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
+#endif
+   }
+   else
+   {
+      size_t i;
+      size_t option_index              = 0;
+      size_t num_options               = 0;
+      struct retro_variable *variables = NULL;
+      char **values_buf                = NULL;
+
+      /* Determine number of options
+       * > Note: We are going to skip a number of irrelevant
+       *   core options when building the retro_variable array,
+       *   but we'll allocate space for all of them. The difference
+       *   in resource usage is negligible, and this allows us to
+       *   keep the code 'cleaner' */
+      for (;;)
+      {
+         if (!option_defs_us[num_options].key)
+            break;
+         num_options++;
+      }
+
+      /* Allocate arrays */
+      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
+      values_buf = (char **)calloc(num_options, sizeof(char *));
+
+      if (!variables || !values_buf)
+         goto error;
+
+      /* Copy parameters from option_defs_us array */
+      for (i = 0; i < num_options; i++)
+      {
+         const char *key                        = option_defs_us[i].key;
+         const char *desc                       = option_defs_us[i].desc;
+         const char *default_value              = option_defs_us[i].default_value;
+         struct retro_core_option_value *values = option_defs_us[i].values;
+         size_t buf_len                         = 3;
+         size_t default_index                   = 0;
+
+         values_buf[i] = NULL;
+
+         /* Skip options that are irrelevant when using the
+          * old style core options interface */
+         if (strcmp(key, "mycore_show_speedhacks") == 0)
+            continue;
+
+         if (desc)
+         {
+            size_t num_values = 0;
+
+            /* Determine number of values */
+            for (;;)
+            {
+               if (!values[num_values].value)
+                  break;
+
+               /* Check if this is the default value */
+               if (default_value)
+                  if (strcmp(values[num_values].value, default_value) == 0)
+                     default_index = num_values;
+
+               buf_len += strlen(values[num_values].value);
+               num_values++;
+            }
+
+            /* Build values string */
+            if (num_values > 0)
+            {
+               size_t j;
+
+               buf_len += num_values - 1;
+               buf_len += strlen(desc);
+
+               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
+               if (!values_buf[i])
+                  goto error;
+
+               strcpy(values_buf[i], desc);
+               strcat(values_buf[i], "; ");
+
+               /* Default value goes first */
+               strcat(values_buf[i], values[default_index].value);
+
+               /* Add remaining values */
+               for (j = 0; j < num_values; j++)
+               {
+                  if (j != default_index)
+                  {
+                     strcat(values_buf[i], "|");
+                     strcat(values_buf[i], values[j].value);
+                  }
+               }
+            }
+         }
+
+         variables[option_index].key   = key;
+         variables[option_index].value = values_buf[i];
+         option_index++;
+      }
+
+      /* Set variables */
+      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
+
+error:
+
+      /* Clean up */
+      if (values_buf)
+      {
+         for (i = 0; i < num_options; i++)
+         {
+            if (values_buf[i])
+            {
+               free(values_buf[i]);
+               values_buf[i] = NULL;
+            }
+         }
+
+         free(values_buf);
+         values_buf = NULL;
+      }
+
+      if (variables)
+      {
+         free(variables);
+         variables = NULL;
+      }
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h b/deps/libretro-common/samples/core_options/example_hide_option/libretro_core_options_intl.h
new file mode 100644 (file)
index 0000000..5288788
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
+#define LIBRETRO_CORE_OPTIONS_INTL_H__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
+/* https://support.microsoft.com/en-us/kb/980263 */
+#pragma execution_character_set("utf-8")
+#pragma warning(disable:4566)
+#endif
+
+#include <libretro.h>
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_JAPANESE */
+
+/* RETRO_LANGUAGE_FRENCH */
+
+/* RETRO_LANGUAGE_SPANISH */
+
+/* RETRO_LANGUAGE_GERMAN */
+
+/* RETRO_LANGUAGE_ITALIAN */
+
+/* RETRO_LANGUAGE_DUTCH */
+
+/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+
+/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+
+/* RETRO_LANGUAGE_RUSSIAN */
+
+/* RETRO_LANGUAGE_KOREAN */
+
+/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+
+/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+
+/* RETRO_LANGUAGE_ESPERANTO */
+
+/* RETRO_LANGUAGE_POLISH */
+
+/* RETRO_LANGUAGE_VIETNAMESE */
+
+/* RETRO_LANGUAGE_ARABIC */
+
+/* RETRO_LANGUAGE_GREEK */
+
+/* RETRO_LANGUAGE_TURKISH */
+
+/* RETRO_LANGUAGE_SLOVAK */
+
+/* RETRO_LANGUAGE_PERSIAN */
+
+/* RETRO_LANGUAGE_HEBREW */
+
+/* RETRO_LANGUAGE_ASTURIAN */
+
+/* RETRO_LANGUAGE_FINNISH */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_translation/libretro_core_options.h b/deps/libretro-common/samples/core_options/example_translation/libretro_core_options.h
new file mode 100644 (file)
index 0000000..7d583cb
--- /dev/null
@@ -0,0 +1,290 @@
+#ifndef LIBRETRO_CORE_OPTIONS_H__
+#define LIBRETRO_CORE_OPTIONS_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libretro.h>
+#include <retro_inline.h>
+
+#ifndef HAVE_NO_LANGEXTRA
+#include "libretro_core_options_intl.h"
+#endif
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_ENGLISH */
+
+/* Default language:
+ * - All other languages must include the same keys and values
+ * - Will be used as a fallback in the event that frontend language
+ *   is not available
+ * - Will be used as a fallback for any missing entries in
+ *   frontend language definition */
+
+struct retro_core_option_definition option_defs_us[] = {
+   {
+      "mycore_region",                            /* key (option name) */
+      "Console Region",                           /* description (label) */
+      "Specify which region the system is from.", /* sublabel */
+      {
+         { "auto",   "Auto" },                    /* value_1, value_1_label */
+         { "ntsc-j", "Japan" },                   /* value_2, value_2_label */
+         { "ntsc-u", "America" },                 /* value_3, value_3_label */
+         { "pal",    "Europe" },                  /* value_4, value_4_label */
+         { NULL, NULL },
+      },
+      "auto"                                      /* default_value */
+   },
+   {
+      "mycore_video_scale",
+      "Video Scale",
+      "Set internal video scale factor.",
+      {
+         { "1x", NULL }, /* If value itself is human-readable (e.g. a number)  */
+         { "2x", NULL }, /* and can displayed directly, the value_label should */
+         { "3x", NULL }, /* be set to NULL                                     */
+         { "4x", NULL },
+         { NULL, NULL },
+      },
+      "3x"
+   },
+   {
+      "mycore_overclock",
+      "Reduce Slowdown",
+      "Enable CPU overclock (unsafe).",
+      {
+         { "enabled",  NULL }, /* If value is equal to 'enabled' or 'disabled', */
+         { "disabled", NULL }, /* value_label should be set to NULL             */
+         { NULL, NULL },
+      },
+      "disabled"
+   },
+   { NULL, NULL, NULL, {{0}}, NULL },
+};
+
+/*
+ ********************************
+ * Language Mapping
+ ********************************
+*/
+
+#ifndef HAVE_NO_LANGEXTRA
+struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
+   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
+   NULL,           /* RETRO_LANGUAGE_JAPANESE */
+   option_defs_fr, /* RETRO_LANGUAGE_FRENCH */
+   NULL,           /* RETRO_LANGUAGE_SPANISH */
+   NULL,           /* RETRO_LANGUAGE_GERMAN */
+   NULL,           /* RETRO_LANGUAGE_ITALIAN */
+   NULL,           /* RETRO_LANGUAGE_DUTCH */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
+   NULL,           /* RETRO_LANGUAGE_KOREAN */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
+   NULL,           /* RETRO_LANGUAGE_POLISH */
+   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
+   NULL,           /* RETRO_LANGUAGE_ARABIC */
+   NULL,           /* RETRO_LANGUAGE_GREEK */
+   NULL,           /* RETRO_LANGUAGE_TURKISH */
+   NULL,           /* RETRO_LANGUAGE_SLOVAK */
+   NULL,           /* RETRO_LANGUAGE_PERSIAN */
+   NULL,           /* RETRO_LANGUAGE_HEBREW */
+   NULL,           /* RETRO_LANGUAGE_ASTURIAN */
+   NULL,           /* RETRO_LANGUAGE_FINNISH */
+   NULL,           /* RETRO_LANGUAGE_INDONESIAN */
+   NULL,           /* RETRO_LANGUAGE_SWEDISH */
+   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
+   NULL,           /* RETRO_LANGUAGE_CZECH */
+};
+#endif
+
+/*
+ ********************************
+ * Functions
+ ********************************
+*/
+
+/* Handles configuration/setting of core options.
+ * Should be called as early as possible - ideally inside
+ * retro_set_environment(), and no later than retro_load_game()
+ * > We place the function body in the header to avoid the
+ *   necessity of adding more .c files (i.e. want this to
+ *   be as painless as possible for core devs)
+ */
+
+static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
+{
+   unsigned version = 0;
+
+   if (!environ_cb)
+      return;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
+   {
+#ifndef HAVE_NO_LANGEXTRA
+      struct retro_core_options_intl core_options_intl;
+      unsigned language = 0;
+
+      core_options_intl.us    = option_defs_us;
+      core_options_intl.local = NULL;
+
+      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
+          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
+         core_options_intl.local = option_defs_intl[language];
+
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
+#else
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
+#endif
+   }
+   else
+   {
+      size_t i;
+      size_t num_options               = 0;
+      struct retro_variable *variables = NULL;
+      char **values_buf                = NULL;
+
+      /* Determine number of options */
+      for (;;)
+      {
+         if (!option_defs_us[num_options].key)
+            break;
+         num_options++;
+      }
+
+      /* Allocate arrays */
+      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
+      values_buf = (char **)calloc(num_options, sizeof(char *));
+
+      if (!variables || !values_buf)
+         goto error;
+
+      /* Copy parameters from option_defs_us array */
+      for (i = 0; i < num_options; i++)
+      {
+         const char *key                        = option_defs_us[i].key;
+         const char *desc                       = option_defs_us[i].desc;
+         const char *default_value              = option_defs_us[i].default_value;
+         struct retro_core_option_value *values = option_defs_us[i].values;
+         size_t buf_len                         = 3;
+         size_t default_index                   = 0;
+
+         values_buf[i] = NULL;
+
+         if (desc)
+         {
+            size_t num_values = 0;
+
+            /* Determine number of values */
+            for (;;)
+            {
+               if (!values[num_values].value)
+                  break;
+
+               /* Check if this is the default value */
+               if (default_value)
+                  if (strcmp(values[num_values].value, default_value) == 0)
+                     default_index = num_values;
+
+               buf_len += strlen(values[num_values].value);
+               num_values++;
+            }
+
+            /* Build values string */
+            if (num_values > 0)
+            {
+               size_t j;
+
+               buf_len += num_values - 1;
+               buf_len += strlen(desc);
+
+               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
+               if (!values_buf[i])
+                  goto error;
+
+               strcpy(values_buf[i], desc);
+               strcat(values_buf[i], "; ");
+
+               /* Default value goes first */
+               strcat(values_buf[i], values[default_index].value);
+
+               /* Add remaining values */
+               for (j = 0; j < num_values; j++)
+               {
+                  if (j != default_index)
+                  {
+                     strcat(values_buf[i], "|");
+                     strcat(values_buf[i], values[j].value);
+                  }
+               }
+            }
+         }
+
+         variables[i].key   = key;
+         variables[i].value = values_buf[i];
+      }
+
+      /* Set variables */
+      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
+
+error:
+
+      /* Clean up */
+      if (values_buf)
+      {
+         for (i = 0; i < num_options; i++)
+         {
+            if (values_buf[i])
+            {
+               free(values_buf[i]);
+               values_buf[i] = NULL;
+            }
+         }
+
+         free(values_buf);
+         values_buf = NULL;
+      }
+
+      if (variables)
+      {
+         free(variables);
+         variables = NULL;
+      }
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h b/deps/libretro-common/samples/core_options/example_translation/libretro_core_options_intl.h
new file mode 100644 (file)
index 0000000..521c8f4
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
+#define LIBRETRO_CORE_OPTIONS_INTL_H__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
+/* https://support.microsoft.com/en-us/kb/980263 */
+#pragma execution_character_set("utf-8")
+#pragma warning(disable:4566)
+#endif
+
+#include <libretro.h>
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_JAPANESE */
+
+/* RETRO_LANGUAGE_FRENCH */
+
+struct retro_core_option_definition option_defs_fr[] = {
+   {
+      "mycore_region",                             /* key must match option_defs_us entry */
+      "Région de la console",                      /* translated description */
+      "Spécifiez la région d'origine du système.", /* translated sublabel */
+      {
+         { "auto",   "Auto" },                     /* value must match option_defs_us entry   */
+         { "ntsc-j", "Japon" },                    /* > only value_label should be translated */
+         { "ntsc-u", "Amérique" },
+         { "pal",    "L'Europe" },
+         { NULL, NULL },
+      },
+      NULL                                         /* default_value is taken from option_defs_us -> can set to NULL here */
+   },
+   {
+      "mycore_video_scale",
+      "Échelle vidéo",
+      "Définir le facteur d'échelle vidéo interne.",
+      {
+         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */
+      },
+      NULL
+   },
+   {
+      "mycore_overclock",
+      "Réduire le ralentissement",
+      "Activer l'overclocking du processeur (non sécurisé).",
+      {
+         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */
+      },
+      NULL
+   },
+   { NULL, NULL, NULL, {{0}}, NULL },
+};
+
+/* RETRO_LANGUAGE_SPANISH */
+
+/* RETRO_LANGUAGE_GERMAN */
+
+/* RETRO_LANGUAGE_ITALIAN */
+
+/* RETRO_LANGUAGE_DUTCH */
+
+/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+
+/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+
+/* RETRO_LANGUAGE_RUSSIAN */
+
+/* RETRO_LANGUAGE_KOREAN */
+
+/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+
+/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+
+/* RETRO_LANGUAGE_ESPERANTO */
+
+/* RETRO_LANGUAGE_POLISH */
+
+/* RETRO_LANGUAGE_VIETNAMESE */
+
+/* RETRO_LANGUAGE_ARABIC */
+
+/* RETRO_LANGUAGE_GREEK */
+
+/* RETRO_LANGUAGE_TURKISH */
+
+/* RETRO_LANGUAGE_SLOVAK */
+
+/* RETRO_LANGUAGE_PERSIAN */
+
+/* RETRO_LANGUAGE_HEBREW */
+
+/* RETRO_LANGUAGE_ASTURIAN */
+
+/* RETRO_LANGUAGE_FINNISH */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_intl.yml b/deps/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_intl.yml
new file mode 100644 (file)
index 0000000..44e9fe9
--- /dev/null
@@ -0,0 +1,41 @@
+# Recreate libretro_core_options_intl.h using translations form Crowdin
+
+name: Crowdin Translation Integration
+
+on:
+  push:
+    branches:
+      - master
+    paths:
+      - 'intl/*/*'
+
+jobs:
+  create_intl_file:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Setup Python
+        uses: actions/setup-python@v2
+        
+      - name: Checkout
+        uses: actions/checkout@v2
+        with:
+          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
+          fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
+
+      - name: Create intl file
+        shell: bash
+        run: |
+          python3 intl/crowdin_intl.py '<path/to/libretro_core_options.h directory>'
+
+      - name: Commit files
+        run: |
+          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
+          git config --local user.name "github-actions[bot]"
+          git add <path/to/libretro_core_options_intl.h file>
+          git commit -m "Recreate libretro_core_options_intl.h" -a
+
+      - name: GitHub Push
+        uses: ad-m/github-push-action@v0.6.0
+        with:
+          github_token: ${{ secrets.GITHUB_TOKEN }}
+          branch: ${{ github.ref }}
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_prep.yml b/deps/libretro-common/samples/core_options/example_translation/translation scripts/.github/workflows/crowdin_prep.yml
new file mode 100644 (file)
index 0000000..86219ee
--- /dev/null
@@ -0,0 +1,41 @@
+# Prepare source for Crowdin sync
+
+name: Crowdin Upload Preparation
+
+on:
+  push:
+    branches:
+      - master
+    paths:
+      - '<path/to/libretro_core_options.h file>'
+
+jobs:
+  prepare_source_file:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Setup Python
+        uses: actions/setup-python@v2
+        
+      - name: Checkout
+        uses: actions/checkout@v2
+        with:
+          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
+          fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
+
+      - name: Crowdin Prep
+        shell: bash
+        run: |
+          python3 intl/crowdin_prep.py '<path/to/libretro_core_options.h directory>'
+          
+      - name: Commit files
+        run: |
+          git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
+          git config --local user.name "github-actions[bot]"
+          git add intl/*
+          git commit -m "Recreate translation source text files" -a
+
+      - name: GitHub Push
+        uses: ad-m/github-push-action@v0.6.0
+        with:
+          github_token: ${{ secrets.GITHUB_TOKEN }}
+          branch: ${{ github.ref }}
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/crowdin.yml b/deps/libretro-common/samples/core_options/example_translation/translation scripts/crowdin.yml
new file mode 100644 (file)
index 0000000..b6e4730
--- /dev/null
@@ -0,0 +1,3 @@
+files:
+  - source: /intl/_us/*.json
+    translation: /intl/_%two_letters_code%/%original_file_name%
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/instructions.txt b/deps/libretro-common/samples/core_options/example_translation/translation scripts/instructions.txt
new file mode 100644 (file)
index 0000000..afd2d11
--- /dev/null
@@ -0,0 +1,47 @@
+Place 'crowdin.yml' & the 'intl' and '.github' folder, including content, into the root of the repo.
+
+In '.github/workflows' are two files: 'crowdin_intl.yml' & 'crowdin_prep.yml'
+In each of those are place holders, which need to be replaced as follows:
+
+<path/to/libretro_core_options.h directory>
+-> replace with the path from the root of the repo to the directory containing
+'libretro_core_options.h' (it is assumed that 'libretro_core_options.h' &
+'libretro_core_options_intl.h' are in the same directory)
+
+<path/to/libretro_core_options.h file>
+-> replace with the full path from the root of the repo to the 'libretro_core_options.h' file
+
+<path/to/libretro_core_options_intl.h file>
+-> replace with the full path from the root of the repo to the 'libretro_core_options_intl.h' file
+
+
+From the root of the repo run (using bash):
+python3 intl/core_opt_translation.py '<path/to/libretro_core_options.h directory>'
+
+(If python3 doesn't work, try just python)
+
+Push changes to repo. Once merged, request Crowdin integration.
+
+
+Crowdin integration:
+
+On the project page, go to the Applications tab. Choose GitHub.
+There are two options: connecting a GitHub account, which has write/commit permissions to the repo
+or providing a GitHub token, which will unlock these permissions.
+
+Then add a repository, a new interface opens. Pick the repository as well as the branch, which you want to sync.
+On the right, Crowdin will display the default name of the repository it will use for creating PRs.
+Below, set the sync schedule and then save. With that the synchronisation should be set up.
+If there are still problems, you might need to manually modify the configuration (double click on the branch in the lower frame).
+
+Here's what the file paths should look like (the '/' at the start is very important!):
+
+Source files path:
+/intl/_us/*.json
+
+Translated files path:
+/intl/_%two_letters_code%/%original_file_name%
+
+
+Once Crowdin successfully creates the PR & it has been merged, the automatically created branch can be deleted on GitHub.
+
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/.gitignore b/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/.gitignore
new file mode 100644 (file)
index 0000000..bee8a64
--- /dev/null
@@ -0,0 +1 @@
+__pycache__
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_opt_translation.py b/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_opt_translation.py
new file mode 100644 (file)
index 0000000..37ec7d1
--- /dev/null
@@ -0,0 +1,609 @@
+#!/usr/bin/env python3
+
+"""Core options text extractor
+
+The purpose of this script is to set up & provide functions for automatic generation of 'libretro_core_options_intl.h'
+from 'libretro_core_options.h' using translations from Crowdin.
+
+Both v1 and v2 structs are supported. It is, however, recommended to convert v1 files to v2 using the included
+'v1_to_v2_converter.py'.
+
+Usage:
+python3 path/to/core_opt_translation.py "path/to/where/libretro_core_options.h & libretro_core_options_intl.h/are"
+
+This script will:
+1.) create key words for & extract the texts from libretro_core_options.h & save them into intl/_us/core_options.h
+2.) do the same for any present translations in libretro_core_options_intl.h, saving those in their respective folder
+"""
+import core_option_regex as cor
+import re
+import os
+import sys
+import json
+import urllib.request as req
+import shutil
+
+# for uploading translations to Crowdin, the Crowdin 'language id' is required
+LANG_CODE_TO_ID = {'_ar': 'ar',
+                   '_ast': 'ast',
+                   '_chs': 'zh-CN',
+                   '_cht': 'zh-TW',
+                   '_cs': 'cs',
+                   '_cy': 'cy',
+                   '_da': 'da',
+                   '_de': 'de',
+                   '_el': 'el',
+                   '_eo': 'eo',
+                   '_es': 'es-ES',
+                   '_fa': 'fa',
+                   '_fi': 'fi',
+                   '_fr': 'fr',
+                   '_gl': 'gl',
+                   '_he': 'he',
+                   '_hu': 'hu',
+                   '_id': 'id',
+                   '_it': 'it',
+                   '_ja': 'ja',
+                   '_ko': 'ko',
+                   '_nl': 'nl',
+                   '_pl': 'pl',
+                   '_pt_br': 'pt-BR',
+                   '_pt_pt': 'pt-PT',
+                   '_ru': 'ru',
+                   '_sk': 'sk',
+                   '_sv': 'sv-SE',
+                   '_tr': 'tr',
+                   '_uk': 'uk',
+                   '_vn': 'vi'}
+LANG_CODE_TO_R_LANG = {'_ar': 'RETRO_LANGUAGE_ARABIC',
+                       '_ast': 'RETRO_LANGUAGE_ASTURIAN',
+                       '_chs': 'RETRO_LANGUAGE_CHINESE_SIMPLIFIED',
+                       '_cht': 'RETRO_LANGUAGE_CHINESE_TRADITIONAL',
+                       '_cs': 'RETRO_LANGUAGE_CZECH',
+                       '_cy': 'RETRO_LANGUAGE_WELSH',
+                       '_da': 'RETRO_LANGUAGE_DANISH',
+                       '_de': 'RETRO_LANGUAGE_GERMAN',
+                       '_el': 'RETRO_LANGUAGE_GREEK',
+                       '_eo': 'RETRO_LANGUAGE_ESPERANTO',
+                       '_es': 'RETRO_LANGUAGE_SPANISH',
+                       '_fa': 'RETRO_LANGUAGE_PERSIAN',
+                       '_fi': 'RETRO_LANGUAGE_FINNISH',
+                       '_fr': 'RETRO_LANGUAGE_FRENCH',
+                       '_gl': 'RETRO_LANGUAGE_GALICIAN',
+                       '_he': 'RETRO_LANGUAGE_HEBREW',
+                       '_hu': 'RETRO_LANGUAGE_HUNGARIAN',
+                       '_id': 'RETRO_LANGUAGE_INDONESIAN',
+                       '_it': 'RETRO_LANGUAGE_ITALIAN',
+                       '_ja': 'RETRO_LANGUAGE_JAPANESE',
+                       '_ko': 'RETRO_LANGUAGE_KOREAN',
+                       '_nl': 'RETRO_LANGUAGE_DUTCH',
+                       '_pl': 'RETRO_LANGUAGE_POLISH',
+                       '_pt_br': 'RETRO_LANGUAGE_PORTUGUESE_BRAZIL',
+                       '_pt_pt': 'RETRO_LANGUAGE_PORTUGUESE_PORTUGAL',
+                       '_ru': 'RETRO_LANGUAGE_RUSSIAN',
+                       '_sk': 'RETRO_LANGUAGE_SLOVAK',
+                       '_sv': 'RETRO_LANGUAGE_SWEDISH',
+                       '_tr': 'RETRO_LANGUAGE_TURKISH',
+                       '_uk': 'RETRO_LANGUAGE_UKRAINIAN',
+                       '_us': 'RETRO_LANGUAGE_ENGLISH',
+                       '_vn': 'RETRO_LANGUAGE_VIETNAMESE'}
+
+# these are handled by RetroArch directly - no need to include them in core translations
+ON_OFFS = {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'}
+
+
+def remove_special_chars(text: str, char_set=0) -> str:
+    """Removes special characters from a text.
+
+    :param text: String to be cleaned.
+    :param char_set: 0 -> remove all ASCII special chars except for '_' & 'space';
+                     1 -> remove invalid chars from file names
+    :return: Clean text.
+    """
+    command_chars = [chr(unicode) for unicode in tuple(range(0, 32)) + (127,)]
+    special_chars = ([chr(unicode) for unicode in tuple(range(33, 48)) + tuple(range(58, 65)) + tuple(range(91, 95))
+                      + (96,) + tuple(range(123, 127))],
+                     ('\\', '/', ':', '*', '?', '"', '<', '>', '|'))
+    res = text
+    for cm in command_chars:
+        res = res.replace(cm, '_')
+    for sp in special_chars[char_set]:
+        res = res.replace(sp, '_')
+    while res.startswith('_'):
+        res = res[1:]
+    while res.endswith('_'):
+        res = res[:-1]
+    return res
+
+
+def clean_file_name(file_name: str) -> str:
+    """Removes characters which might make file_name inappropriate for files on some OS.
+
+    :param file_name: File name to be cleaned.
+    :return: The clean file name.
+    """
+    file_name = remove_special_chars(file_name, 1)
+    file_name = re.sub(r'__+', '_', file_name.replace(' ', '_'))
+    return file_name
+
+
+def get_struct_type_name(decl: str) -> tuple:
+    """ Returns relevant parts of the struct declaration:
+    type, name of the struct and the language appendix, if present.
+    :param decl: The struct declaration matched by cor.p_type_name.
+    :return: Tuple, e.g.: ('retro_core_option_definition', 'option_defs_us', '_us')
+    """
+    struct_match = cor.p_type_name.search(decl)
+    if struct_match:
+        if struct_match.group(3):
+            struct_type_name = struct_match.group(1, 2, 3)
+            return struct_type_name
+        elif struct_match.group(4):
+            struct_type_name = struct_match.group(1, 2, 4)
+            return struct_type_name
+        else:
+            struct_type_name = struct_match.group(1, 2)
+            return struct_type_name
+    else:
+        raise ValueError(f'No or incomplete struct declaration: {decl}!\n'
+                         'Please make sure all structs are complete, including the type and name declaration.')
+
+
+def is_viable_non_dupe(text: str, comparison) -> bool:
+    """text must be longer than 2 ('""'), not 'NULL' and not in comparison.
+
+    :param text: String to be tested.
+    :param comparison: Dictionary or set to search for text in.
+    :return: bool
+    """
+    return 2 < len(text) and text != 'NULL' and text not in comparison
+
+
+def is_viable_value(text: str) -> bool:
+    """text must be longer than 2 ('""'), not 'NULL' and text.lower() not in
+    {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'}.
+
+    :param text: String to be tested.
+    :return: bool
+    """
+    return 2 < len(text) and text != 'NULL' and text.lower() not in ON_OFFS
+
+
+def create_non_dupe(base_name: str, opt_num: int, comparison) -> str:
+    """Makes sure base_name is not in comparison, and if it is it's renamed.
+
+    :param base_name: Name to check/make unique.
+    :param opt_num: Number of the option base_name belongs to, used in making it unique.
+    :param comparison: Dictionary or set to search for base_name in.
+    :return: Unique name.
+    """
+    h = base_name
+    if h in comparison:
+        n = 0
+        h = h + '_O' + str(opt_num)
+        h_end = len(h)
+        while h in comparison:
+            h = h[:h_end] + '_' + str(n)
+            n += 1
+    return h
+
+
+def get_texts(text: str) -> dict:
+    """Extracts the strings, which are to be translated/are the translations,
+    from text and creates macro names for them.
+
+    :param text: The string to be parsed.
+    :return: Dictionary of the form { '_<lang>': { 'macro': 'string', ... }, ... }.
+    """
+    # all structs: group(0) full struct, group(1) beginning, group(2) content
+    structs = cor.p_struct.finditer(text)
+    hash_n_string = {}
+    just_string = {}
+    for struct in structs:
+        struct_declaration = struct.group(1)
+        struct_type_name = get_struct_type_name(struct_declaration)
+        if 3 > len(struct_type_name):
+            lang = '_us'
+        else:
+            lang = struct_type_name[2]
+        if lang not in just_string:
+            hash_n_string[lang] = {}
+            just_string[lang] = set()
+
+        is_v2 = False
+        pre_name = ''
+        p = cor.p_info
+        if 'retro_core_option_v2_definition' == struct_type_name[0]:
+            is_v2 = True
+        elif 'retro_core_option_v2_category' == struct_type_name[0]:
+            pre_name = 'CATEGORY_'
+            p = cor.p_info_cat
+
+        struct_content = struct.group(2)
+        # 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
+        struct_options = cor.p_option.finditer(struct_content)
+        for opt, option in enumerate(struct_options):
+            # group 1: key
+            if option.group(1):
+                opt_name = pre_name + option.group(1)
+                # no special chars allowed in key
+                opt_name = remove_special_chars(opt_name).upper().replace(' ', '_')
+            else:
+                raise ValueError(f'No option name (key) found in struct {struct_type_name[1]} option {opt}!')
+
+            # group 2: description0
+            if option.group(2):
+                desc0 = option.group(2)
+                if is_viable_non_dupe(desc0, just_string[lang]):
+                    just_string[lang].add(desc0)
+                    m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL'), opt, hash_n_string[lang])
+                    hash_n_string[lang][m_h] = desc0
+            else:
+                raise ValueError(f'No label found in struct {struct_type_name[1]} option {option.group(1)}!')
+
+            # group 3: desc1, info0, info1, category
+            if option.group(3):
+                infos = option.group(3)
+                option_info = p.finditer(infos)
+                if is_v2:
+                    desc1 = next(option_info).group(1)
+                    if is_viable_non_dupe(desc1, just_string[lang]):
+                        just_string[lang].add(desc1)
+                        m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL_CAT'), opt, hash_n_string[lang])
+                        hash_n_string[lang][m_h] = desc1
+                    last = None
+                    m_h = None
+                    for j, info in enumerate(option_info):
+                        last = info.group(1)
+                        if is_viable_non_dupe(last, just_string[lang]):
+                            just_string[lang].add(last)
+                            m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,
+                                                  hash_n_string[lang])
+                            hash_n_string[lang][m_h] = last
+                    if last in just_string[lang]:  # category key should not be translated
+                        hash_n_string[lang].pop(m_h)
+                        just_string[lang].remove(last)
+                else:
+                    for j, info in enumerate(option_info):
+                        gr1 = info.group(1)
+                        if is_viable_non_dupe(gr1, just_string[lang]):
+                            just_string[lang].add(gr1)
+                            m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,
+                                                  hash_n_string[lang])
+                            hash_n_string[lang][m_h] = gr1
+            else:
+                raise ValueError(f'Too few arguments in struct {struct_type_name[1]} option {option.group(1)}!')
+
+            # group 4:
+            if option.group(4):
+                for j, kv_set in enumerate(cor.p_key_value.finditer(option.group(4))):
+                    set_key, set_value = kv_set.group(1, 2)
+                    if not is_viable_value(set_value):
+                        if not is_viable_value(set_key):
+                            continue
+                        set_value = set_key
+                    # re.fullmatch(r'(?:[+-][0-9]+)+', value[1:-1])
+                    if set_value not in just_string[lang] and not re.sub(r'[+-]', '', set_value[1:-1]).isdigit():
+                        clean_key = set_key.encode('ascii', errors='ignore').decode('unicode-escape')[1:-1]
+                        clean_key = remove_special_chars(clean_key).upper().replace(' ', '_')
+                        m_h = create_non_dupe(re.sub(r'__+', '_', f"OPTION_VAL_{clean_key}"), opt, hash_n_string[lang])
+                        hash_n_string[lang][m_h] = set_value
+                        just_string[lang].add(set_value)
+    return hash_n_string
+
+
+def create_msg_hash(intl_dir_path: str, core_name: str, keyword_string_dict: dict) -> dict:
+    """Creates '<core_name>.h' files in 'intl/_<lang>/' containing the macro name & string combinations.
+
+    :param intl_dir_path: Path to the intl directory.
+    :param core_name: Name of the core, used for naming the files.
+    :param keyword_string_dict: Dictionary of the form { '_<lang>': { 'macro': 'string', ... }, ... }.
+    :return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.
+    """
+    files = {}
+    for localisation in keyword_string_dict:
+        path = os.path.join(intl_dir_path, localisation)  # intl/_<lang>
+        files[localisation] = os.path.join(path, core_name + '.h')  # intl/_<lang>/<core_name>.h
+        if not os.path.exists(path):
+            os.makedirs(path)
+        with open(files[localisation], 'w', encoding='utf-8') as crowdin_file:
+            out_text = ''
+            for keyword in keyword_string_dict[localisation]:
+                out_text = f'{out_text}{keyword} {keyword_string_dict[localisation][keyword]}\n'
+            crowdin_file.write(out_text)
+    return files
+
+
+def h2json(file_paths: dict) -> dict:
+    """Converts .h files pointed to by file_paths into .jsons.
+
+    :param file_paths: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.
+    :return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.json)', ... }.
+    """
+    jsons = {}
+    for file_lang in file_paths:
+        jsons[file_lang] = file_paths[file_lang][:-2] + '.json'
+
+        p = cor.p_masked
+
+        with open(file_paths[file_lang], 'r+', encoding='utf-8') as h_file:
+            text = h_file.read()
+            result = p.finditer(text)
+            messages = {}
+            for msg in result:
+                key, val = msg.group(1, 2)
+                if key not in messages:
+                    if key and val:
+                        # unescape & remove "\n"
+                        messages[key] = re.sub(r'"\s*(?:(?:/\*(?:.|[\r\n])*?\*/|//.*[\r\n]+)\s*)*"',
+                                               '\\\n', val[1:-1].replace('\\\"', '"'))
+                else:
+                    print(f"DUPLICATE KEY in {file_paths[file_lang]}: {key}")
+            with open(jsons[file_lang], 'w', encoding='utf-8') as json_file:
+                json.dump(messages, json_file, indent=2)
+
+    return jsons
+
+
+def json2h(intl_dir_path: str, json_file_path: str, core_name: str) -> None:
+    """Converts .json file in json_file_path into an .h ready to be included in C code.
+
+    :param intl_dir_path: Path to the intl directory.
+    :param json_file_path: Base path of translation .json.
+    :param core_name: Name of the core, required for naming the files.
+    :return: None
+    """
+    h_filename = os.path.join(json_file_path, core_name + '.h')
+    json_filename = os.path.join(json_file_path, core_name + '.json')
+    file_lang = os.path.basename(json_file_path).upper()
+
+    if os.path.basename(json_file_path).lower() == '_us':
+        print('    skipped')
+        return
+
+    p = cor.p_masked
+
+    def update(s_messages, s_template, s_source_messages):
+        translation = ''
+        template_messages = p.finditer(s_template)
+        for tp_msg in template_messages:
+            old_key = tp_msg.group(1)
+            if old_key in s_messages and s_messages[old_key] != s_source_messages[old_key]:
+                tl_msg_val = s_messages[old_key]
+                tl_msg_val = tl_msg_val.replace('"', '\\\"').replace('\n', '')  # escape
+                translation = ''.join((translation, '#define ', old_key, file_lang, f' "{tl_msg_val}"\n'))
+
+            else:  # Remove English duplicates and non-translatable strings
+                translation = ''.join((translation, '#define ', old_key, file_lang, ' NULL\n'))
+        return translation
+
+    with open(os.path.join(intl_dir_path, '_us', core_name + '.h'), 'r', encoding='utf-8') as template_file:
+        template = template_file.read()
+    with open(os.path.join(intl_dir_path, '_us', core_name + '.json'), 'r+', encoding='utf-8') as source_json_file:
+        source_messages = json.load(source_json_file)
+    with open(json_filename, 'r+', encoding='utf-8') as json_file:
+        messages = json.load(json_file)
+        new_translation = update(messages, template, source_messages)
+    with open(h_filename, 'w', encoding='utf-8') as h_file:
+        h_file.seek(0)
+        h_file.write(new_translation)
+        h_file.truncate()
+    return
+
+
+def get_crowdin_client(dir_path: str) -> str:
+    """Makes sure the Crowdin CLI client is present. If it isn't, it is fetched & extracted.
+
+    :return: The path to 'crowdin-cli.jar'.
+    """
+    jar_name = 'crowdin-cli.jar'
+    jar_path = os.path.join(dir_path, jar_name)
+
+    if not os.path.isfile(jar_path):
+        print('Downloading crowdin-cli.jar')
+        crowdin_cli_file = os.path.join(dir_path, 'crowdin-cli.zip')
+        crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/crowdin-cli.zip'
+        req.urlretrieve(crowdin_cli_url, crowdin_cli_file)
+        import zipfile
+        with zipfile.ZipFile(crowdin_cli_file, 'r') as zip_ref:
+            jar_dir = zip_ref.namelist()[0]
+            for file in zip_ref.namelist():
+                if file.endswith(jar_name):
+                    jar_file = file
+                    break
+            zip_ref.extract(jar_file)
+            os.rename(jar_file, jar_path)
+            os.remove(crowdin_cli_file)
+            shutil.rmtree(jar_dir)
+    return jar_path
+
+
+def create_intl_file(intl_file_path: str, intl_dir_path: str, text: str, core_name: str, file_path: str) -> None:
+    """Creates 'libretro_core_options_intl.h' from Crowdin translations.
+
+    :param intl_file_path: Path to 'libretro_core_options_intl.h'
+    :param intl_dir_path: Path to the intl directory.
+    :param text: Content of the 'libretro_core_options.h' being translated.
+    :param core_name: Name of the core. Needed to identify the files to pull the translations from.
+    :param file_path: Path to the '<core name>_us.h' file, containing the original English texts.
+    :return: None
+    """
+    msg_dict = {}
+    lang_up = ''
+
+    def replace_pair(pair_match):
+        """Replaces a key-value-pair of an option with the macros corresponding to the language.
+
+        :param pair_match: The re match object representing the key-value-pair block.
+        :return: Replacement string.
+        """
+        offset = pair_match.start(0)
+        if pair_match.group(1):  # key
+            if pair_match.group(2) in msg_dict:  # value
+                val = msg_dict[pair_match.group(2)] + lang_up
+            elif pair_match.group(1) in msg_dict:  # use key if value not viable (e.g. NULL)
+                val = msg_dict[pair_match.group(1)] + lang_up
+            else:
+                return pair_match.group(0)
+        else:
+            return pair_match.group(0)
+        res = pair_match.group(0)[:pair_match.start(2) - offset] + val \
+            + pair_match.group(0)[pair_match.end(2) - offset:]
+        return res
+
+    def replace_info(info_match):
+        """Replaces the 'additional strings' of an option with the macros corresponding to the language.
+
+        :param info_match: The re match object representing the 'additional strings' block.
+        :return: Replacement string.
+        """
+        offset = info_match.start(0)
+        if info_match.group(1) in msg_dict:
+            res = info_match.group(0)[:info_match.start(1) - offset] + \
+                  msg_dict[info_match.group(1)] + lang_up + \
+                  info_match.group(0)[info_match.end(1) - offset:]
+            return res
+        else:
+            return info_match.group(0)
+
+    def replace_option(option_match):
+        """Replaces strings within an option
+        '{ "opt_key", "label", "additional strings", ..., { {"key", "value"}, ... }, ... }'
+        within a struct with the macros corresponding to the language:
+        '{ "opt_key", MACRO_LABEL, MACRO_STRINGS, ..., { {"key", MACRO_VALUE}, ... }, ... }'
+
+        :param option_match: The re match object representing the option.
+        :return: Replacement string.
+        """
+        # label
+        offset = option_match.start(0)
+        if option_match.group(2):
+            res = option_match.group(0)[:option_match.start(2) - offset] + msg_dict[option_match.group(2)] + lang_up
+        else:
+            return option_match.group(0)
+        # additional block
+        if option_match.group(3):
+            res = res + option_match.group(0)[option_match.end(2) - offset:option_match.start(3) - offset]
+            new_info = p.sub(replace_info, option_match.group(3))
+            res = res + new_info
+        else:
+            return res + option_match.group(0)[option_match.end(2) - offset:]
+        # key-value-pairs
+        if option_match.group(4):
+            res = res + option_match.group(0)[option_match.end(3) - offset:option_match.start(4) - offset]
+            new_pairs = cor.p_key_value.sub(replace_pair, option_match.group(4))
+            res = res + new_pairs + option_match.group(0)[option_match.end(4) - offset:]
+        else:
+            res = res + option_match.group(0)[option_match.end(3) - offset:]
+
+        return res
+
+    with open(file_path, 'r+', encoding='utf-8') as template:  # intl/_us/<core_name>.h
+        masked_msgs = cor.p_masked.finditer(template.read())
+        for msg in masked_msgs:
+            msg_dict[msg.group(2)] = msg.group(1)
+
+    with open(intl_file_path, 'r', encoding='utf-8') as intl:  # libretro_core_options_intl.h
+        in_text = intl.read()
+        intl_start = re.search(re.escape('/*\n'
+                                         ' ********************************\n'
+                                         ' * Core Option Definitions\n'
+                                         ' ********************************\n'
+                                         '*/\n'), in_text)
+        if intl_start:
+            out_txt = in_text[:intl_start.end(0)]
+        else:
+            intl_start = re.search(re.escape('#ifdef __cplusplus\n'
+                                             'extern "C" {\n'
+                                             '#endif\n'), in_text)
+            out_txt = in_text[:intl_start.end(0)]
+
+    for folder in os.listdir(intl_dir_path):  # intl/_*
+        if os.path.isdir(os.path.join(intl_dir_path, folder)) and folder.startswith('_')\
+                and folder != '_us' and folder != '__pycache__':
+            translation_path = os.path.join(intl_dir_path, folder, core_name + '.h')  # <core_name>_<lang>.h
+            # all structs: group(0) full struct, group(1) beginning, group(2) content
+            struct_groups = cor.p_struct.finditer(text)
+            lang_up = folder.upper()
+            lang_low = folder.lower()
+            out_txt = out_txt + f'/* {LANG_CODE_TO_R_LANG[lang_low]} */\n\n'  # /* RETRO_LANGUAGE_NAME */
+            with open(translation_path, 'r+', encoding='utf-8') as f_in:  # <core name>.h
+                out_txt = out_txt + f_in.read() + '\n'
+            for construct in struct_groups:
+                declaration = construct.group(1)
+                struct_type_name = get_struct_type_name(declaration)
+                if 3 > len(struct_type_name):  # no language specifier
+                    new_decl = re.sub(re.escape(struct_type_name[1]), struct_type_name[1] + lang_low, declaration)
+                else:
+                    new_decl = re.sub(re.escape(struct_type_name[2]), lang_low, declaration)
+                    if '_us' != struct_type_name[2]:
+                        continue
+
+                p = cor.p_info
+                if 'retro_core_option_v2_category' == struct_type_name[0]:
+                    p = cor.p_info_cat
+                offset_construct = construct.start(0)
+                start = construct.end(1) - offset_construct
+                end = construct.start(2) - offset_construct
+                out_txt = out_txt + new_decl + construct.group(0)[start:end]
+
+                content = construct.group(2)
+                new_content = cor.p_option.sub(replace_option, content)
+
+                start = construct.end(2) - offset_construct
+                out_txt = out_txt + new_content + construct.group(0)[start:] + '\n'
+
+                if 'retro_core_option_v2_definition' == struct_type_name[0]:
+                    out_txt = out_txt + f'struct retro_core_options_v2 options{lang_low}' \
+                                        ' = {\n' \
+                                        f'   option_cats{lang_low},\n' \
+                                        f'   option_defs{lang_low}\n' \
+                                        '};\n\n'
+        #    shutil.rmtree(JOINER.join((intl_dir_path, folder)))
+
+    with open(intl_file_path, 'w', encoding='utf-8') as intl:
+        intl.write(out_txt + '\n#ifdef __cplusplus\n'
+                             '}\n#endif\n'
+                             '\n#endif')
+    return
+
+
+# --------------------          MAIN          -------------------- #
+
+if __name__ == '__main__':
+    #
+    try:
+        if os.path.isfile(sys.argv[1]):
+            _temp = os.path.dirname(sys.argv[1])
+        else:
+            _temp = sys.argv[1]
+        while _temp.endswith('/') or _temp.endswith('\\'):
+            _temp = _temp[:-1]
+        TARGET_DIR_PATH = _temp
+    except IndexError:
+        TARGET_DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)
+
+    DIR_PATH = os.path.dirname(os.path.realpath(__file__))
+    H_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')
+    INTL_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')
+
+    _core_name = 'core_options'
+    try:
+        print('Getting texts from libretro_core_options.h')
+        with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
+            _main_text = _h_file.read()
+        _hash_n_str = get_texts(_main_text)
+        _files = create_msg_hash(DIR_PATH, _core_name, _hash_n_str)
+        _source_jsons = h2json(_files)
+    except Exception as e:
+        print(e)
+
+    print('Getting texts from libretro_core_options_intl.h')
+    with open(INTL_FILE_PATH, 'r+', encoding='utf-8') as _intl_file:
+        _intl_text = _intl_file.read()
+        _hash_n_str_intl = get_texts(_intl_text)
+        _intl_files = create_msg_hash(DIR_PATH, _core_name, _hash_n_str_intl)
+        _intl_jsons = h2json(_intl_files)
+
+    print('\nAll done!')
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_option_regex.py b/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/core_option_regex.py
new file mode 100644 (file)
index 0000000..34a3f20
--- /dev/null
@@ -0,0 +1,95 @@
+import re
+
+# 0: full struct; 1: up to & including first []; 2: content between first {}
+p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*'
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
+                      r'=\s*'  # =
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*'
+                      r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};')  # captures full struct, it's beginning and it's content
+# 0: type name[]; 1: type; 2: name
+p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*'
+                         r'(option_cats([a-z_]{0,8})|option_defs([a-z_]{0,8}))\s*\[]')
+# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs
+p_option = re.compile(r'{\s*'  # opening braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(\".*?\"|'  # key start; group 1
+                      r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|'
+                      r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|'
+                      r'[a-zA-Z0-9_]+\s*\".*?\")\s*'  # key end
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(\".*?\")\s*'  # description; group 2
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'((?:'  # group 3
+                      r'(?:NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r')+)'
+                      r'(?:'  # defs only start
+                      r'{\s*'  # opening braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'((?:'  # key/value pairs start; group 4
+                      r'{\s*'  # opening braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(?:NULL|\".*?\")\s*'  # option key
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(?:NULL|\".*?\")\s*'  # option value
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'}\s*'  # closing braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r')*)'  # key/value pairs end
+                      r'}\s*'  # closing braces
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r'(?:'  # defaults start
+                      r'(?:NULL|\".*?\")\s*'  # default value
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r',?\s*'  # comma
+                      r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                      r')*'  # defaults end
+                      r')?'  # defs only end
+                      r'},')  # closing braces
+# analyse option group 3
+p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*'  # description in category, info, info in category, category
+                    r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                    r',')
+p_info_cat = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")')
+# analyse option group 4
+p_key_value = re.compile(r'{\s*'  # opening braces
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r'(NULL|\".*?\")\s*'  # option key; 1
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r',\s*'  # comma
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r'(NULL|\".*?\")\s*'  # option value; 2
+                         r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*'
+                         r'}')
+
+p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")')
+
+p_intl = re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {'
+                    r'((?:.|[\r\n])*?)};')
+p_set = re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)'
+                   r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif')
+
+p_yaml = re.compile(r'"project_id": "[0-9]+".*\s*'
+                    r'"api_token": "([a-zA-Z0-9]+)".*\s*'
+                    r'"base_path": "\./intl".*\s*'
+                    r'"base_url": "https://api\.crowdin\.com".*\s*'
+                    r'"preserve_hierarchy": true.*\s*'
+                    r'"files": \[\s*'
+                    r'\{\s*'
+                    r'"source": "/_us/\*\.json",.*\s*'
+                    r'"translation": "/_%two_letters_code%/%original_file_name%",.*\s*'
+                    r'"skip_untranslated_strings": true.*\s*'
+                    r'},\s*'
+                    r']')
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_intl.py b/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_intl.py
new file mode 100644 (file)
index 0000000..f4605f7
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+import core_opt_translation as t
+
+
+if __name__ == '__main__':
+    try:
+        if t.os.path.isfile(t.sys.argv[1]):
+            _temp = t.os.path.dirname(t.sys.argv[1])
+        else:
+            _temp = t.sys.argv[1]
+        while _temp.endswith('/') or _temp.endswith('\\'):
+            _temp = _temp[:-1]
+        TARGET_DIR_PATH = _temp
+    except IndexError:
+        TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))
+        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)
+
+    DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))
+    H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')
+    INTL_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')
+
+    _core_name = 'core_options'
+    _core_name = t.clean_file_name(_core_name)
+
+    print('Getting texts from libretro_core_options.h')
+    with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
+        _main_text = _h_file.read()
+    _hash_n_str = t.get_texts(_main_text)
+    _files = t.create_msg_hash(DIR_PATH, _core_name, _hash_n_str)
+
+    print('Converting translations *.json to *.h:')
+    for _folder in t.os.listdir(DIR_PATH):
+        if t.os.path.isdir(t.os.path.join(DIR_PATH, _folder))\
+                and _folder.startswith('_')\
+                and _folder != '__pycache__':
+            print(_folder)
+            t.json2h(DIR_PATH, t.os.path.join(DIR_PATH, _folder), _core_name)
+
+    print('Constructing libretro_core_options_intl.h')
+    t.create_intl_file(INTL_FILE_PATH, DIR_PATH, _main_text, _core_name, _files['_us'])
+
+    print('\nAll done!')
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_prep.py b/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/crowdin_prep.py
new file mode 100644 (file)
index 0000000..9c0b41d
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+
+import core_opt_translation as t
+
+
+if __name__ == '__main__':
+    _core_name = 'core_options'
+
+    try:
+        if t.os.path.isfile(t.sys.argv[1]):
+            _temp = t.os.path.dirname(t.sys.argv[1])
+        else:
+            _temp = t.sys.argv[1]
+        while _temp.endswith('/') or _temp.endswith('\\'):
+            _temp = _temp[:-1]
+        TARGET_DIR_PATH = _temp
+    except IndexError:
+        TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))
+        print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH)
+
+    DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))
+    H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')
+
+    _core_name = t.clean_file_name(_core_name)
+
+    print('Getting texts from libretro_core_options.h')
+    with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:
+        _main_text = _h_file.read()
+    _hash_n_str = t.get_texts(_main_text)
+    _files = t.create_msg_hash(DIR_PATH, _core_name, _hash_n_str)
+
+    _source_jsons = t.h2json(_files)
+
+    print('\nAll done!')
diff --git a/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/v1_to_v2_converter.py b/deps/libretro-common/samples/core_options/example_translation/translation scripts/intl/v1_to_v2_converter.py
new file mode 100644 (file)
index 0000000..2b1556e
--- /dev/null
@@ -0,0 +1,459 @@
+#!/usr/bin/env python3
+
+"""Core options v1 to v2 converter
+
+Just run this script as follows, to convert 'libretro_core_options.h' & 'Libretro_coreoptions_intl.h' to v2:
+python3 "/path/to/v1_to_v2_converter.py" "/path/to/where/libretro_core_options.h & Libretro_coreoptions_intl.h/are"
+
+The original files will be preserved as *.v1
+"""
+import core_option_regex as cor
+import os
+import sys
+
+
+def create_v2_code_file(struct_text, file_name):
+    def replace_option(option_match):
+        _offset = option_match.start(0)
+
+        if option_match.group(3):
+            res = option_match.group(0)[:option_match.end(2) - _offset] + ',\n      NULL' + \
+                  option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \
+                  'NULL,\n      NULL,\n      ' + option_match.group(0)[option_match.end(3) - _offset:]
+        else:
+            return option_match.group(0)
+
+        return res
+
+    comment_v1 = '/*\n' \
+                 ' ********************************\n' \
+                 ' * VERSION: 1.3\n' \
+                 ' ********************************\n' \
+                 ' *\n' \
+                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
+                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
+                 ' *          fix for MSVC 2010-2013\n' \
+                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
+                 ' *          on platforms/compilers without BOM support\n' \
+                 ' * - 1.2: Use core options v1 interface when\n' \
+                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
+                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
+                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
+                 ' *        arrays containing options with a single value\n' \
+                 ' * - 1.0: First commit\n' \
+                 '*/\n'
+
+    comment_v2 = '/*\n' \
+                 ' ********************************\n' \
+                 ' * VERSION: 2.0\n' \
+                 ' ********************************\n' \
+                 ' *\n' \
+                 ' * - 2.0: Add support for core options v2 interface\n' \
+                 ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \
+                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\n' \
+                 ' *          fix for MSVC 2010-2013\n' \
+                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \
+                 ' *          on platforms/compilers without BOM support\n' \
+                 ' * - 1.2: Use core options v1 interface when\n' \
+                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \
+                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \
+                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \
+                 ' *        arrays containing options with a single value\n' \
+                 ' * - 1.0: First commit\n' \
+                 '*/\n'
+
+    p_intl = cor.p_intl
+    p_set = cor.p_set
+    new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\n' \
+              '      bool *categories_supported)\n' \
+              '{\n' \
+              '   unsigned version  = 0;\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '   unsigned language = 0;\n' \
+              '#endif\n' \
+              '\n' \
+              '   if (!environ_cb || !categories_supported)\n' \
+              '      return;\n' \
+              '\n' \
+              '   *categories_supported = false;\n' \
+              '\n' \
+              '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))\n' \
+              '      version = 0;\n' \
+              '\n' \
+              '   if (version >= 2)\n' \
+              '   {\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '      struct retro_core_options_v2_intl core_options_intl;\n' \
+              '\n' \
+              '      core_options_intl.us    = &options_us;\n' \
+              '      core_options_intl.local = NULL;\n' \
+              '\n' \
+              '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
+              '          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))\n' \
+              '         core_options_intl.local = options_intl[language];\n' \
+              '\n' \
+              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n' \
+              '            &core_options_intl);\n' \
+              '#else\n' \
+              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n' \
+              '            &options_us);\n' \
+              '#endif\n' \
+              '   }\n' \
+              '   else\n' \
+              '   {\n' \
+              '      size_t i, j;\n' \
+              '      size_t option_index              = 0;\n' \
+              '      size_t num_options               = 0;\n' \
+              '      struct retro_core_option_definition\n' \
+              '            *option_v1_defs_us         = NULL;\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '      size_t num_options_intl          = 0;\n' \
+              '      struct retro_core_option_v2_definition\n' \
+              '            *option_defs_intl          = NULL;\n' \
+              '      struct retro_core_option_definition\n' \
+              '            *option_v1_defs_intl       = NULL;\n' \
+              '      struct retro_core_options_intl\n' \
+              '            core_options_v1_intl;\n' \
+              '#endif\n' \
+              '      struct retro_variable *variables = NULL;\n' \
+              '      char **values_buf                = NULL;\n' \
+              '\n' \
+              '      /* Determine total number of options */\n' \
+              '      while (true)\n' \
+              '      {\n' \
+              '         if (option_defs_us[num_options].key)\n' \
+              '            num_options++;\n' \
+              '         else\n' \
+              '            break;\n' \
+              '      }\n' \
+              '\n' \
+              '      if (version >= 1)\n' \
+              '      {\n' \
+              '         /* Allocate US array */\n' \
+              '         option_v1_defs_us = (struct retro_core_option_definition *)\n' \
+              '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\n' \
+              '\n' \
+              '         /* Copy parameters from option_defs_us array */\n' \
+              '         for (i = 0; i < num_options; i++)\n' \
+              '         {\n' \
+              '            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];\n' \
+              '            struct retro_core_option_value *option_values         = option_def_us->values;\n' \
+              '            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];\n' \
+              '            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;\n' \
+              '\n' \
+              '            option_v1_def_us->key           = option_def_us->key;\n' \
+              '            option_v1_def_us->desc          = option_def_us->desc;\n' \
+              '            option_v1_def_us->info          = option_def_us->info;\n' \
+              '            option_v1_def_us->default_value = option_def_us->default_value;\n' \
+              '\n' \
+              '            /* Values must be copied individually... */\n' \
+              '            while (option_values->value)\n' \
+              '            {\n' \
+              '               option_v1_values->value = option_values->value;\n' \
+              '               option_v1_values->label = option_values->label;\n' \
+              '\n' \
+              '               option_values++;\n' \
+              '               option_v1_values++;\n' \
+              '            }\n' \
+              '         }\n' \
+              '\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \
+              '             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&\n' \
+              '             options_intl[language])\n' \
+              '            option_defs_intl = options_intl[language]->definitions;\n' \
+              '\n' \
+              '         if (option_defs_intl)\n' \
+              '         {\n' \
+              '            /* Determine number of intl options */\n' \
+              '            while (true)\n' \
+              '            {\n' \
+              '               if (option_defs_intl[num_options_intl].key)\n' \
+              '                  num_options_intl++;\n' \
+              '               else\n' \
+              '                  break;\n' \
+              '            }\n' \
+              '\n' \
+              '            /* Allocate intl array */\n' \
+              '            option_v1_defs_intl = (struct retro_core_option_definition *)\n' \
+              '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\n' \
+              '\n' \
+              '            /* Copy parameters from option_defs_intl array */\n' \
+              '            for (i = 0; i < num_options_intl; i++)\n' \
+              '            {\n' \
+              '               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];\n' \
+              '               struct retro_core_option_value *option_values           = option_def_intl->values;\n' \
+              '               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];\n' \
+              '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;\n' \
+              '\n' \
+              '               option_v1_def_intl->key           = option_def_intl->key;\n' \
+              '               option_v1_def_intl->desc          = option_def_intl->desc;\n' \
+              '               option_v1_def_intl->info          = option_def_intl->info;\n' \
+              '               option_v1_def_intl->default_value = option_def_intl->default_value;\n' \
+              '\n' \
+              '               /* Values must be copied individually... */\n' \
+              '               while (option_values->value)\n' \
+              '               {\n' \
+              '                  option_v1_values->value = option_values->value;\n' \
+              '                  option_v1_values->label = option_values->label;\n' \
+              '\n' \
+              '                  option_values++;\n' \
+              '                  option_v1_values++;\n' \
+              '               }\n' \
+              '            }\n' \
+              '         }\n' \
+              '\n' \
+              '         core_options_v1_intl.us    = option_v1_defs_us;\n' \
+              '         core_options_v1_intl.local = option_v1_defs_intl;\n' \
+              '\n' \
+              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);\n' \
+              '#else\n' \
+              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\n' \
+              '#endif\n' \
+              '      }\n' \
+              '      else\n' \
+              '      {\n' \
+              '         /* Allocate arrays */\n' \
+              '         variables  = (struct retro_variable *)calloc(num_options + 1,\n' \
+              '               sizeof(struct retro_variable));\n' \
+              '         values_buf = (char **)calloc(num_options, sizeof(char *));\n' \
+              '\n' \
+              '         if (!variables || !values_buf)\n' \
+              '            goto error;\n' \
+              '\n' \
+              '         /* Copy parameters from option_defs_us array */\n' \
+              '         for (i = 0; i < num_options; i++)\n' \
+              '         {\n' \
+              '            const char *key                        = option_defs_us[i].key;\n' \
+              '            const char *desc                       = option_defs_us[i].desc;\n' \
+              '            const char *default_value              = option_defs_us[i].default_value;\n' \
+              '            struct retro_core_option_value *values = option_defs_us[i].values;\n' \
+              '            size_t buf_len                         = 3;\n' \
+              '            size_t default_index                   = 0;\n' \
+              '\n' \
+              '            values_buf[i] = NULL;\n' \
+              '\n' \
+              '            if (desc)\n' \
+              '            {\n' \
+              '               size_t num_values = 0;\n' \
+              '\n' \
+              '               /* Determine number of values */\n' \
+              '               while (true)\n' \
+              '               {\n' \
+              '                  if (values[num_values].value)\n' \
+              '                  {\n' \
+              '                     /* Check if this is the default value */\n' \
+              '                     if (default_value)\n' \
+              '                        if (strcmp(values[num_values].value, default_value) == 0)\n' \
+              '                           default_index = num_values;\n' \
+              '\n' \
+              '                     buf_len += strlen(values[num_values].value);\n' \
+              '                     num_values++;\n' \
+              '                  }\n' \
+              '                  else\n' \
+              '                     break;\n' \
+              '               }\n' \
+              '\n' \
+              '               /* Build values string */\n' \
+              '               if (num_values > 0)\n' \
+              '               {\n' \
+              '                  buf_len += num_values - 1;\n' \
+              '                  buf_len += strlen(desc);\n' \
+              '\n' \
+              '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\n' \
+              '                  if (!values_buf[i])\n' \
+              '                     goto error;\n' \
+              '\n' \
+              '                  strcpy(values_buf[i], desc);\n' \
+              '                  strcat(values_buf[i], "; ");\n' \
+              '\n' \
+              '                  /* Default value goes first */\n' \
+              '                  strcat(values_buf[i], values[default_index].value);\n' \
+              '\n' \
+              '                  /* Add remaining values */\n' \
+              '                  for (j = 0; j < num_values; j++)\n' \
+              '                  {\n' \
+              '                     if (j != default_index)\n' \
+              '                     {\n' \
+              '                        strcat(values_buf[i], "|");\n' \
+              '                        strcat(values_buf[i], values[j].value);\n' \
+              '                     }\n' \
+              '                  }\n' \
+              '               }\n' \
+              '            }\n' \
+              '\n' \
+              '            variables[option_index].key   = key;\n' \
+              '            variables[option_index].value = values_buf[i];\n' \
+              '            option_index++;\n' \
+              '         }\n' \
+              '\n' \
+              '         /* Set variables */\n' \
+              '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n' \
+              '      }\n' \
+              '\n' \
+              'error:\n' \
+              '      /* Clean up */\n' \
+              '\n' \
+              '      if (option_v1_defs_us)\n' \
+              '      {\n' \
+              '         free(option_v1_defs_us);\n' \
+              '         option_v1_defs_us = NULL;\n' \
+              '      }\n' \
+              '\n' \
+              '#ifndef HAVE_NO_LANGEXTRA\n' \
+              '      if (option_v1_defs_intl)\n' \
+              '      {\n' \
+              '         free(option_v1_defs_intl);\n' \
+              '         option_v1_defs_intl = NULL;\n' \
+              '      }\n' \
+              '#endif\n' \
+              '\n' \
+              '      if (values_buf)\n' \
+              '      {\n' \
+              '         for (i = 0; i < num_options; i++)\n' \
+              '         {\n' \
+              '            if (values_buf[i])\n' \
+              '            {\n' \
+              '               free(values_buf[i]);\n' \
+              '               values_buf[i] = NULL;\n' \
+              '            }\n' \
+              '         }\n' \
+              '\n' \
+              '         free(values_buf);\n' \
+              '         values_buf = NULL;\n' \
+              '      }\n' \
+              '\n' \
+              '      if (variables)\n' \
+              '      {\n' \
+              '         free(variables);\n' \
+              '         variables = NULL;\n' \
+              '      }\n' \
+              '   }\n' \
+              '}\n' \
+              '\n' \
+              '#ifdef __cplusplus\n' \
+              '}\n' \
+              '#endif'
+
+    struct_groups = cor.p_struct.finditer(struct_text)
+    out_text = struct_text
+
+    for construct in struct_groups:
+        repl_text = ''
+        declaration = construct.group(1)
+        struct_match = cor.p_type_name.search(declaration)
+        if struct_match:
+            if struct_match.group(3):
+                struct_type_name_lang = struct_match.group(1, 2, 3)
+                declaration_end = declaration[struct_match.end(1):]
+            elif struct_match.group(4):
+                struct_type_name_lang = struct_match.group(1, 2, 4)
+                declaration_end = declaration[struct_match.end(1):]
+            else:
+                struct_type_name_lang = sum((struct_match.group(1, 2), ('_us',)), ())
+                declaration_end = f'{declaration[struct_match.end(1):struct_match.end(2)]}_us' \
+                                  f'{declaration[struct_match.end(2):]}'
+        else:
+            return -1
+
+        if 'retro_core_option_definition' == struct_type_name_lang[0]:
+            import shutil
+            shutil.copy(file_name, file_name + '.v1')
+            new_declaration = f'\nstruct retro_core_option_v2_category option_cats{struct_type_name_lang[2]}[] = ' \
+                              '{\n   { NULL, NULL, NULL },\n' \
+                              '};\n\n' \
+                              + declaration[:struct_match.start(1)] + \
+                              'retro_core_option_v2_definition' \
+                              + declaration_end
+            offset = construct.start(0)
+            repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,
+                                               construct.group(0)[:construct.start(2) - offset])
+            content = construct.group(2)
+            new_content = cor.p_option.sub(replace_option, content)
+
+            repl_text = repl_text + new_content + cor.re.sub(r'{\s*NULL,\s*NULL,\s*NULL,\s*{\{0}},\s*NULL\s*},\s*};',
+                                                             '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};'
+                                                             '\n\nstruct retro_core_options_v2 options' +
+                                                             struct_type_name_lang[2] + ' = {\n'
+                                                             f'   option_cats{struct_type_name_lang[2]},\n'
+                                                             f'   option_defs{struct_type_name_lang[2]}\n'
+                                                             '};',
+                                                             construct.group(0)[construct.end(2) - offset:])
+            out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text)
+        else:
+            return -2
+    with open(file_name, 'w', encoding='utf-8') as code_file:
+        out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)
+        intl = p_intl.search(out_text)
+        if intl:
+            new_intl = out_text[:intl.start(1)] \
+                       + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \
+                       + out_text[intl.end(1):intl.start(2)] \
+                       + '&options_us, /* RETRO_LANGUAGE_ENGLISH */' \
+                       '   &options_ja,      /* RETRO_LANGUAGE_JAPANESE */' \
+                       '   &options_fr,      /* RETRO_LANGUAGE_FRENCH */' \
+                       '   &options_es,      /* RETRO_LANGUAGE_SPANISH */' \
+                       '   &options_de,      /* RETRO_LANGUAGE_GERMAN */' \
+                       '   &options_it,      /* RETRO_LANGUAGE_ITALIAN */' \
+                       '   &options_nl,      /* RETRO_LANGUAGE_DUTCH */' \
+                       '   &options_pt_br,   /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */' \
+                       '   &options_pt_pt,   /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */' \
+                       '   &options_ru,      /* RETRO_LANGUAGE_RUSSIAN */' \
+                       '   &options_ko,      /* RETRO_LANGUAGE_KOREAN */' \
+                       '   &options_cht,     /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */' \
+                       '   &options_chs,     /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */' \
+                       '   &options_eo,      /* RETRO_LANGUAGE_ESPERANTO */' \
+                       '   &options_pl,      /* RETRO_LANGUAGE_POLISH */' \
+                       '   &options_vn,      /* RETRO_LANGUAGE_VIETNAMESE */' \
+                       '   &options_ar,      /* RETRO_LANGUAGE_ARABIC */' \
+                       '   &options_el,      /* RETRO_LANGUAGE_GREEK */' \
+                       '   &options_tr,      /* RETRO_LANGUAGE_TURKISH */' \
+                       '   &options_sv,      /* RETRO_LANGUAGE_SLOVAK */' \
+                       '   &options_fa,      /* RETRO_LANGUAGE_PERSIAN */' \
+                       '   &options_he,      /* RETRO_LANGUAGE_HEBREW */' \
+                       '   &options_ast,     /* RETRO_LANGUAGE_ASTURIAN */' \
+                       '   &options_fi,      /* RETRO_LANGUAGE_FINNISH */' \
+                       + out_text[intl.end(2):]
+            out_text = p_set.sub(new_set, new_intl)
+        else:
+            out_text = p_set.sub(new_set, out_text)
+        code_file.write(out_text)
+
+    return 1
+
+
+# --------------------          MAIN          -------------------- #
+
+if __name__ == '__main__':
+    try:
+        if os.path.isfile(sys.argv[1]):
+            _temp = os.path.dirname(sys.argv[1])
+        else:
+            _temp = sys.argv[1]
+        while _temp.endswith('/') or _temp.endswith('\\'):
+            _temp = _temp[:-1]
+        DIR_PATH = _temp
+    except IndexError:
+        DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+        print("No path provided, assuming parent directory:\n" + DIR_PATH)
+
+    H_FILE_PATH = os.path.join(DIR_PATH, 'libretro_core_options.h')
+    INTL_FILE_PATH = os.path.join(DIR_PATH, 'libretro_core_options_intl.h')
+
+    for file in (H_FILE_PATH, INTL_FILE_PATH):
+        if os.path.isfile(file):
+            with open(file, 'r+', encoding='utf-8') as h_file:
+                text = h_file.read()
+                try:
+                    test = create_v2_code_file(text, file)
+                except Exception as e:
+                    print(e)
+                    test = -1
+                if -1 > test:
+                    print('Your file looks like it already is v2? (' + file + ')')
+                    continue
+                if 0 > test:
+                    print('An error occured! Please make sure to use the complete v1 struct! (' + file + ')')
+                    continue
+        else:
+            print(file + ' not found.')
diff --git a/deps/libretro-common/samples/file/config_file/Makefile b/deps/libretro-common/samples/file/config_file/Makefile
new file mode 100644 (file)
index 0000000..d4a605f
--- /dev/null
@@ -0,0 +1,36 @@
+TARGET := config_file_test
+
+LIBRETRO_COMM_DIR := ../../..
+
+SOURCES := \
+       config_file_test.c \
+       $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
+       $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
+       $(LIBRETRO_COMM_DIR)/file/file_path.c \
+       $(LIBRETRO_COMM_DIR)/file/file_path_io.c \
+       $(LIBRETRO_COMM_DIR)/file/config_file.c \
+       $(LIBRETRO_COMM_DIR)/lists/string_list.c \
+       $(LIBRETRO_COMM_DIR)/string/stdstring.c \
+       $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
+       $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
+       $(LIBRETRO_COMM_DIR)/time/rtime.c
+
+OBJS := $(SOURCES:.c=.o)
+
+CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/file/config_file/config_file_test.c b/deps/libretro-common/samples/file/config_file/config_file_test.c
new file mode 100644 (file)
index 0000000..8699406
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (config_file_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <file/config_file.h>
+
+static void test_config_file_parse_contains(
+      const char *cfgtext,
+      const char *key, const char *val)
+{
+   char *cfgtext_copy = strdup(cfgtext);
+   config_file_t *cfg = config_file_new_from_string(cfgtext_copy, NULL);
+   char          *out = NULL;
+   bool            ok = false;
+
+   free(cfgtext_copy);
+
+   if (!cfg)
+      abort();
+
+   ok = config_get_string(cfg, key, &out);
+   if (ok != (bool)val)
+      abort();
+   if (!val)
+      return;
+
+   if (!out)
+      out = strdup("");
+   if (strcmp(out, val) != 0)
+   {
+      printf("[FAILED] Key [%s] Doesn't contain val [%s]\n", key, val);
+      abort();
+   }
+   printf("[SUCCESS] Key [%s] contains val [%s]\n", key, val);
+   free(out);
+}
+
+int main(void)
+{
+   test_config_file_parse_contains("foo = \"bar\"\n",   "foo", "bar");
+   test_config_file_parse_contains("foo = \"bar\"",     "foo", "bar");
+   test_config_file_parse_contains("foo = \"bar\"\r\n", "foo", "bar");
+   test_config_file_parse_contains("foo = \"bar\"",     "foo", "bar");
+
+   test_config_file_parse_contains("foo = \"\"\n",   "foo", "");
+   test_config_file_parse_contains("foo = \"\"",     "foo", "");
+   test_config_file_parse_contains("foo = \"\"\r\n", "foo", "");
+   test_config_file_parse_contains("foo = \"\"",     "foo", "");
+
+   test_config_file_parse_contains("foo = \"\"\n",   "bar", NULL);
+   test_config_file_parse_contains("foo = \"\"",     "bar", NULL);
+   test_config_file_parse_contains("foo = \"\"\r\n", "bar", NULL);
+   test_config_file_parse_contains("foo = \"\"",     "bar", NULL);
+}
diff --git a/deps/libretro-common/samples/file/nbio/Makefile b/deps/libretro-common/samples/file/nbio/Makefile
new file mode 100644 (file)
index 0000000..c0a9021
--- /dev/null
@@ -0,0 +1,31 @@
+TARGET := nbio_test
+
+LIBRETRO_COMM_DIR := ../../..
+
+SOURCES := \
+       nbio_test.c \
+       $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
+       $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c
+
+OBJS := $(SOURCES:.c=.o)
+
+CFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/file/nbio/nbio_test.c b/deps/libretro-common/samples/file/nbio/nbio_test.c
new file mode 100644 (file)
index 0000000..dbb3cf3
--- /dev/null
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <file/nbio.h>
+
+static void nbio_write_test(void)
+{
+   size_t size;
+   bool looped = false;
+   void* ptr = NULL;
+   struct nbio_t* write = nbio_open("test.bin", NBIO_WRITE);
+   if (!write)
+      puts("[ERROR]: nbio_open failed (1)");
+
+   nbio_resize(write, 1024*1024);
+
+   ptr = nbio_get_ptr(write, &size);
+   if (size != 1024*1024)
+      puts("[ERROR]: wrong size (1)");
+
+   memset(ptr, 0x42, 1024*1024);
+   nbio_begin_write(write);
+
+   while (!nbio_iterate(write))
+      looped=true;
+
+   if (!looped)
+      puts("[SUCCESS]: Write finished immediately.");
+
+   nbio_free(write);
+}
+
+static void nbio_read_test(void)
+{
+   size_t size;
+   bool looped = false;
+   struct nbio_t* read = nbio_open("test.bin", NBIO_READ);
+   void* ptr           = nbio_get_ptr(read, &size);
+   if (!read)
+      puts("[ERROR]: nbio_open failed (2)");
+
+   if (size != 1024*1024)
+      puts("[ERROR]: wrong size (2)");
+   if (ptr)
+      puts("[SUCCESS]: Read pointer is available before iterating.");
+
+   nbio_begin_read(read);
+
+   while (!nbio_iterate(read))
+      looped=true;
+
+   if (!looped)
+      puts("[SUCCESS]: Read finished immediately.");
+
+   ptr = nbio_get_ptr(read, &size);
+
+   if (size != 1024*1024)
+      puts("[ERROR]: wrong size (3)");
+   if (*(char*)ptr != 0x42 || memcmp(ptr, (char*)ptr+1, 1024*1024-1))
+      puts("[ERROR]: wrong data");
+
+   nbio_free(read);
+}
+
+int main(void)
+{
+   nbio_write_test();
+   nbio_read_test();
+}
diff --git a/deps/libretro-common/samples/formats/png/Makefile b/deps/libretro-common/samples/formats/png/Makefile
new file mode 100644 (file)
index 0000000..1a4bbba
--- /dev/null
@@ -0,0 +1,60 @@
+TARGET := rpng
+
+CORE_DIR          := .
+LIBRETRO_PNG_DIR  := ../../../formats/png
+LIBRETRO_COMM_DIR := ../../..
+
+HAVE_IMLIB2=0
+
+LDFLAGS +=  -lz
+
+ifeq ($(HAVE_IMLIB2),1)
+CFLAGS += -DHAVE_IMLIB2
+LDFLAGS += -lImlib2
+endif
+
+SOURCES_C :=   \
+       $(CORE_DIR)/rpng_test.c \
+       $(LIBRETRO_PNG_DIR)/rpng.c \
+       $(LIBRETRO_PNG_DIR)/rpng_encode.c \
+       $(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
+       $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
+       $(LIBRETRO_COMM_DIR)/string/stdstring.c \
+       $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \
+       $(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \
+       $(LIBRETRO_COMM_DIR)/file/archive_file.c \
+       $(LIBRETRO_COMM_DIR)/file/archive_file_zlib.c \
+       $(LIBRETRO_COMM_DIR)/file/file_path.c \
+       $(LIBRETRO_COMM_DIR)/file/file_path_io.c \
+       $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
+       $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
+       $(LIBRETRO_COMM_DIR)/streams/interface_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/memory_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
+       $(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
+       $(LIBRETRO_COMM_DIR)/lists/string_list.c
+
+OBJS := $(SOURCES_C:.c=.o)
+
+CFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB -DRPNG_TEST -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/formats/png/rpng_test.c b/deps/libretro-common/samples/formats/png/rpng_test.c
new file mode 100644 (file)
index 0000000..066a799
--- /dev/null
@@ -0,0 +1,207 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rpng_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#ifdef HAVE_IMLIB2
+#include <Imlib2.h>
+#endif
+
+#include <file/nbio.h>
+#include <formats/rpng.h>
+#include <formats/image.h>
+
+static bool rpng_load_image_argb(const char *path, uint32_t **data,
+      unsigned *width, unsigned *height)
+{
+   int retval;
+   size_t file_len;
+   bool              ret = true;
+   rpng_t          *rpng = NULL;
+   void             *ptr = NULL;
+   struct nbio_t* handle = (struct nbio_t*)nbio_open(path, NBIO_READ);
+
+   if (!handle)
+      goto end;
+
+   nbio_begin_read(handle);
+
+   while (!nbio_iterate(handle));
+
+   ptr = nbio_get_ptr(handle, &file_len);
+
+   if (!ptr)
+   {
+      ret = false;
+      goto end;
+   }
+
+   rpng = rpng_alloc();
+
+   if (!rpng)
+   {
+      ret = false;
+      goto end;
+   }
+
+   if (!rpng_set_buf_ptr(rpng, (uint8_t*)ptr, file_len))
+   {
+      ret = false;
+      goto end;
+   }
+
+   if (!rpng_start(rpng))
+   {
+      ret = false;
+      goto end;
+   }
+
+   while (rpng_iterate_image(rpng));
+
+   if (!rpng_is_valid(rpng))
+   {
+      ret = false;
+      goto end;
+   }
+
+   do
+   {
+      retval = rpng_process_image(rpng,
+            (void**)data, file_len, width, height);
+   }while(retval == IMAGE_PROCESS_NEXT);
+
+   if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)
+      ret = false;
+
+end:
+   if (handle)
+      nbio_free(handle);
+   if (rpng)
+      rpng_free(rpng);
+   rpng = NULL;
+   if (!ret)
+      free(*data);
+   return ret;
+}
+
+static int test_rpng(const char *in_path)
+{
+#ifdef HAVE_IMLIB2
+   Imlib_Image img;
+   const uint32_t *imlib_data = NULL;
+#endif
+   const uint32_t test_data[] = {
+      0xff000000 | 0x50, 0xff000000 | 0x80,
+      0xff000000 | 0x40, 0xff000000 | 0x88,
+      0xff000000 | 0x50, 0xff000000 | 0x80,
+      0xff000000 | 0x40, 0xff000000 | 0x88,
+      0xff000000 | 0xc3, 0xff000000 | 0xd3,
+      0xff000000 | 0xc3, 0xff000000 | 0xd3,
+      0xff000000 | 0xc3, 0xff000000 | 0xd3,
+      0xff000000 | 0xc3, 0xff000000 | 0xd3,
+   };
+   uint32_t *data = NULL;
+   unsigned width = 0;
+   unsigned height = 0;
+
+   if (!rpng_save_image_argb("/tmp/test.png", test_data, 4, 4, 16))
+      return 1;
+
+   if (!rpng_load_image_argb(in_path, &data, &width, &height))
+      return 2;
+
+   fprintf(stderr, "Path: %s.\n", in_path);
+   fprintf(stderr, "Got image: %u x %u.\n", width, height);
+
+#if 0
+   fprintf(stderr, "\nRPNG:\n");
+   for (unsigned h = 0; h < height; h++)
+   {
+      unsigned w;
+      for (w = 0; w < width; w++)
+         fprintf(stderr, "[%08x] ", data[h * width + w]);
+      fprintf(stderr, "\n");
+   }
+#endif
+
+#ifdef HAVE_IMLIB2
+   /* Validate with imlib2 as well. */
+   img = imlib_load_image(in_path);
+   if (!img)
+      return 4;
+
+   imlib_context_set_image(img);
+
+   width      = imlib_image_get_width();
+   height     = imlib_image_get_width();
+   imlib_data = imlib_image_get_data_for_reading_only();
+
+#if 0
+   fprintf(stderr, "\nImlib:\n");
+   for (unsigned h = 0; h < height; h++)
+   {
+      for (unsigned w = 0; w < width; w++)
+         fprintf(stderr, "[%08x] ", imlib_data[h * width + w]);
+      fprintf(stderr, "\n");
+   }
+#endif
+
+   if (memcmp(imlib_data, data, width * height * sizeof(uint32_t)) != 0)
+   {
+      fprintf(stderr, "Imlib and RPNG differs!\n");
+      return 5;
+   }
+   else
+      fprintf(stderr, "Imlib and RPNG are equivalent!\n");
+
+   imlib_free_image();
+#endif
+   free(data);
+
+   return 0;
+}
+
+int main(int argc, char *argv[])
+{
+   const char *in_path = "/tmp/test.png";
+
+   if (argc > 2)
+   {
+      fprintf(stderr, "Usage: %s <png file>\n", argv[0]);
+      return 1;
+   }
+
+   if (argc == 2)
+      in_path = argv[1];
+
+   fprintf(stderr, "Doing tests...\n");
+
+   if (test_rpng(in_path) != 0)
+   {
+      fprintf(stderr, "Test failed.\n");
+      return -1;
+   }
+
+   return 0;
+}
diff --git a/deps/libretro-common/samples/formats/xml/Makefile b/deps/libretro-common/samples/formats/xml/Makefile
new file mode 100644 (file)
index 0000000..f311f5d
--- /dev/null
@@ -0,0 +1,32 @@
+TARGET := rxml
+
+LIBRETRO_XML_DIR  := ../../../formats/xml
+LIBRETRO_COMM_DIR := ../../../
+LIBRETRO_DEPS_DIR := ../../../../deps
+
+SOURCES := \
+       rxml_test.c \
+       $(LIBRETRO_XML_DIR)/rxml.c \
+       $(LIBRETRO_DEPS_DIR)/yxml/yxml.c \
+       $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
+       $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
+       $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
+       $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c
+
+OBJS := $(SOURCES:.c=.o)
+
+CFLAGS += -DRXML_TEST -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/formats/xml/rxml_test.c b/deps/libretro-common/samples/formats/xml/rxml_test.c
new file mode 100644 (file)
index 0000000..ed1ec8b
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rxml_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <formats/rxml.h>
+#include <stdio.h>
+
+static void print_siblings(struct rxml_node *node, unsigned level)
+{
+   fprintf(stderr, "\n%*sName: %s\n", level * 4, "", node->name);
+   if (node->data)
+      fprintf(stderr, "%*sData: %s\n", level * 4, "", node->data);
+
+   for (const struct rxml_attrib_node *attrib =
+         node->attrib; attrib; attrib = attrib->next)
+      fprintf(stderr, "%*s  Attrib: %s = %s\n", level * 4, "",
+            attrib->attrib, attrib->value);
+
+   if (node->children)
+      print_siblings(node->children, level + 1);
+
+   if (node->next)
+      print_siblings(node->next, level);
+}
+
+static void rxml_log_document(const char *path)
+{
+   rxml_document_t *doc = rxml_load_document(path);
+   if (!doc)
+   {
+      fprintf(stderr, "rxml: Failed to load document: %s\n", path);
+      return;
+   }
+
+   print_siblings(rxml_root_node(doc), 0);
+   rxml_free_document(doc);
+}
+
+int main(int argc, char *argv[])
+{
+   if (argc != 2)
+   {
+      fprintf(stderr, "Usage: %s <path>\n", argv[0]);
+      return 1;
+   }
+
+   rxml_log_document(argv[1]);
+}
diff --git a/deps/libretro-common/samples/net/Makefile b/deps/libretro-common/samples/net/Makefile
new file mode 100644 (file)
index 0000000..6c523d5
--- /dev/null
@@ -0,0 +1,80 @@
+TARGETS  = http_test http_parse_test net_ifinfo
+
+LIBRETRO_COMM_DIR := ../..
+
+INCFLAGS = -I$(LIBRETRO_COMM_DIR)/include
+
+ifeq ($(platform),)
+platform = unix
+ifeq ($(shell uname -a),)
+   platform = win
+else ifneq ($(findstring Darwin,$(shell uname -a)),)
+   platform = osx
+       arch = intel
+ifeq ($(shell uname -p),powerpc)
+       arch = ppc
+endif
+else ifneq ($(findstring MINGW,$(shell uname -a)),)
+   platform = win
+endif
+endif
+
+ifeq ($(DEBUG),1)
+CFLAGS += -O0 -g
+else
+CFLAGS += -O2
+endif
+CFLAGS += -Wall -pedantic -std=gnu99
+
+HTTP_TEST_C = \
+                                 $(LIBRETRO_COMM_DIR)/net/net_http.c \
+                                 $(LIBRETRO_COMM_DIR)/net/net_compat.c \
+                                 $(LIBRETRO_COMM_DIR)/net/net_socket.c \
+                                 $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
+                                 $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
+                                 $(LIBRETRO_COMM_DIR)/string/stdstring.c \
+                                 net_http_test.c
+
+HTTP_TEST_OBJS := $(HTTP_TEST_C:.c=.o)
+
+HTTP_PARSE_TEST_C = \
+                                 $(LIBRETRO_COMM_DIR)/net/net_http.c \
+                                 $(LIBRETRO_COMM_DIR)/net/net_http_parse.c \
+                                 $(LIBRETRO_COMM_DIR)/net/net_compat.c \
+                                 $(LIBRETRO_COMM_DIR)/net/net_socket.c \
+                                 $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
+                                 $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
+                                 $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
+                                 $(LIBRETRO_COMM_DIR)/string/stdstring.c \
+                                 net_http_parse_test.c
+
+HTTP_PARSE_TEST_OBJS := $(HTTP_PARSE_TEST_C:.c=.o)
+
+NET_IFINFO_C = \
+                                       $(LIBRETRO_COMM_DIR)/net/net_ifinfo.c \
+                                       net_ifinfo_test.c
+
+ifeq ($(platform), win)
+CFLAGS += -liphlpapi -lws2_32
+endif
+
+NET_IFINFO_OBJS := $(NET_IFINFO_C:.c=.o)
+
+.PHONY: all clean
+
+all: $(TARGETS)
+
+%.o: %.c
+       $(CC) $(INCFLAGS) $< -c $(CFLAGS) -o $@
+
+http_parse_test: $(HTTP_PARSE_TEST_OBJS)
+       $(CC) $(INCFLAGS) $(HTTP_PARSE_TEST_OBJS) $(CFLAGS) -o $@
+
+http_test: $(HTTP_TEST_OBJS)
+       $(CC) $(INCFLAGS) $(HTTP_TEST_OBJS) $(CFLAGS) -o $@
+
+net_ifinfo: $(NET_IFINFO_OBJS)
+       $(CC) $(INCFLAGS) $(NET_IFINFO_OBJS) $(CFLAGS) -o $@
+
+clean:
+       rm -rf $(TARGETS) $(HTTP_TEST_OBJS) $(HTTP_PARSE_TEST_OBJS) $(NET_IFINFO_OBJS)
diff --git a/deps/libretro-common/samples/net/http_test b/deps/libretro-common/samples/net/http_test
new file mode 100644 (file)
index 0000000..bcdeb81
Binary files /dev/null and b/deps/libretro-common/samples/net/http_test differ
diff --git a/deps/libretro-common/samples/net/net_http_parse_test.c b/deps/libretro-common/samples/net/net_http_parse_test.c
new file mode 100644 (file)
index 0000000..014b89f
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_http_parse_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <compat/strcasestr.h>
+
+int main(int argc, char *argv[])
+{
+   char link[1024];
+   char name[1024];
+   const char *line  = "<a href=\"http://www.test.com/somefile.zip\">Test</a>\n";
+
+   link[0] = name[0] = '\0';
+
+   string_parse_html_anchor(line, link, name, sizeof(link), sizeof(name));
+
+   printf("link: %s\nname: %s\n", link, name);
+
+   return 1;
+}
diff --git a/deps/libretro-common/samples/net/net_http_test.c b/deps/libretro-common/samples/net/net_http_test.c
new file mode 100644 (file)
index 0000000..ebd0167
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_http_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <net/net_http.h>
+#include <net/net_compat.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+
+int main(void)
+{
+   char   *data;
+   struct http_t *http1, *http3;
+   size_t len, pos = 0, tot = 0;
+
+   if (!network_init())
+      return -1;
+
+   http1 = net_http_new("http://buildbot.libretro.com/nightly/windows/x86_64/latest/mednafen_psx_libretro.dll.zip");
+
+   while (!net_http_update(http1, &pos, &tot))
+      printf("%.9lu / %.9lu        \r",pos,tot);
+
+   http3 = net_http_new("http://www.wikipedia.org/");
+   while (!net_http_update(http3, NULL, NULL)) {}
+
+   data  = (char*)net_http_data(http3, &len, false);
+
+   printf("%.*s\n", (int)256, data);
+
+   net_http_delete(http1);
+   net_http_delete(http3);
+
+   return 0;
+}
diff --git a/deps/libretro-common/samples/net/net_ifinfo b/deps/libretro-common/samples/net/net_ifinfo
new file mode 100644 (file)
index 0000000..0b8dc0e
Binary files /dev/null and b/deps/libretro-common/samples/net/net_ifinfo differ
diff --git a/deps/libretro-common/samples/net/net_ifinfo_test.c b/deps/libretro-common/samples/net/net_ifinfo_test.c
new file mode 100644 (file)
index 0000000..3705209
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (net_ifinfo_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/net_ifinfo.h>
+
+int main(int argc, const char *argv[])
+{
+   unsigned k              = 0;
+   net_ifinfo_t list;
+
+   if (!net_ifinfo_new(&list))
+      return -1;
+
+   for (k = 0; k < list.size; k++)
+   {
+      printf("%s:%s\n", list.entries[k].name, list.entries[k].host);
+   }
+
+   net_ifinfo_free(&list);
+
+   return 0;
+}
diff --git a/deps/libretro-common/samples/net/udp-test.c b/deps/libretro-common/samples/net/udp-test.c
new file mode 100644 (file)
index 0000000..3366cf5
--- /dev/null
@@ -0,0 +1,55 @@
+/* public domain */
+/* gcc -o udptest udp-test.c */
+
+/*
+   will send "RETROPAD RIGHT" indefinely to player 1
+   to send to player 2 change port to 55401 and so on
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#define SERVER "127.0.0.1"
+#define PORT 55400
+
+void die(char *s)
+{
+    perror(s);
+    exit(1);
+}
+
+int main(void)
+{
+   struct sockaddr_in si_other;
+   int s, i, slen=sizeof(si_other);
+
+   if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+      die("socket");
+
+   memset((char *) &si_other, 0, sizeof(si_other));
+   si_other.sin_family = AF_INET;
+   si_other.sin_port = htons(PORT);
+
+   if (inet_aton(SERVER , &si_other.sin_addr) == 0)
+   {
+      fprintf(stderr, "inet_aton() failed\n");
+      exit(1);
+   }
+
+   for (;;)
+   {
+      char message[10]="128";
+      /* send the message */
+      if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other, slen)==-1)
+         die("sendto()");
+
+      /* sleep for 1 frame (60hz) */
+      usleep(16*1000);
+   }
+
+   close(s);
+   return 0;
+}
diff --git a/deps/libretro-common/samples/streams/rzip/Makefile b/deps/libretro-common/samples/streams/rzip/Makefile
new file mode 100644 (file)
index 0000000..2d5d180
--- /dev/null
@@ -0,0 +1,102 @@
+TARGET := rzip
+
+LIBRETRO_COMM_DIR := ../../..
+LIBRETRO_DEPS_DIR := ../../../../deps
+
+# Attempt to detect target platform
+ifeq '$(findstring ;,$(PATH))' ';'
+       UNAME := Windows
+else
+       UNAME := $(shell uname 2>/dev/null || echo Unknown)
+       UNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))
+       UNAME := $(patsubst MSYS%,MSYS,$(UNAME))
+       UNAME := $(patsubst MINGW%,MSYS,$(UNAME))
+endif
+
+# Add '.exe' extension on Windows platforms
+ifeq ($(UNAME), Windows)
+       TARGET := rzip.exe
+endif
+ifeq ($(UNAME), MSYS)
+       TARGET := rzip.exe
+endif
+
+SOURCES := \
+       rzip.c \
+       $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
+       $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \
+       $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
+       $(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \
+       $(LIBRETRO_COMM_DIR)/file/file_path.c \
+       $(LIBRETRO_COMM_DIR)/file/file_path_io.c \
+       $(LIBRETRO_COMM_DIR)/string/stdstring.c \
+       $(LIBRETRO_COMM_DIR)/streams/file_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \
+       $(LIBRETRO_COMM_DIR)/streams/interface_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/memory_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/rzip_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/stdin_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
+       $(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
+       $(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
+       $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
+       $(LIBRETRO_COMM_DIR)/time/rtime.c
+
+ifneq ($(wildcard $(LIBRETRO_DEPS_DIR)/*),)
+       # If we are building from inside the RetroArch
+       # directory (i.e. if an 'external' deps directory
+       # is avaiable), bake in zlib support
+       SOURCES += \
+               $(LIBRETRO_DEPS_DIR)/libz/adler32.c \
+               $(LIBRETRO_DEPS_DIR)/libz/libz-crc32.c \
+               $(LIBRETRO_DEPS_DIR)/libz/deflate.c \
+               $(LIBRETRO_DEPS_DIR)/libz/gzclose.c \
+               $(LIBRETRO_DEPS_DIR)/libz/gzlib.c \
+               $(LIBRETRO_DEPS_DIR)/libz/gzread.c \
+               $(LIBRETRO_DEPS_DIR)/libz/gzwrite.c \
+               $(LIBRETRO_DEPS_DIR)/libz/inffast.c \
+               $(LIBRETRO_DEPS_DIR)/libz/inflate.c \
+               $(LIBRETRO_DEPS_DIR)/libz/inftrees.c \
+               $(LIBRETRO_DEPS_DIR)/libz/trees.c \
+               $(LIBRETRO_DEPS_DIR)/libz/zutil.c
+       INCLUDE_DIRS := -I$(LIBRETRO_COMM_DIR)/include/compat/zlib
+else
+       # If this is a stand-alone libretro-common directory,
+       # rely on system zlib library (note: only likely to
+       # work on Unix-based platforms...)
+       LDFLAGS += -lz
+endif
+
+OBJS := $(SOURCES:.c=.o)
+INCLUDE_DIRS += -I$(LIBRETRO_COMM_DIR)/include
+CFLAGS += -DHAVE_ZLIB -Wall -pedantic -std=gnu99 $(INCLUDE_DIRS)
+
+# Silence "ISO C does not support the 'I64' ms_printf length modifier"
+# warnings when using MinGW
+ifeq ($(UNAME), Windows)
+       CFLAGS += -Wno-format
+endif
+ifeq ($(UNAME), MSYS)
+       CFLAGS += -Wno-format
+endif
+
+ifeq ($(DEBUG), 1)
+       CFLAGS += -O0 -g -DDEBUG -D_DEBUG
+else
+       CFLAGS += -O2 -DNDEBUG
+endif
+
+all: $(TARGET)
+
+%.o: %.c
+       $(CC) -c -o $@ $< $(CFLAGS)
+
+$(TARGET): $(OBJS)
+       $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+       rm -f $(TARGET) $(OBJS)
+
+.PHONY: clean
diff --git a/deps/libretro-common/samples/streams/rzip/rzip.c b/deps/libretro-common/samples/streams/rzip/rzip.c
new file mode 100644 (file)
index 0000000..0d6bdd5
--- /dev/null
@@ -0,0 +1,362 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (config_file_test.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <time.h>
+
+#include <string/stdstring.h>
+#include <file/file_path.h>
+#include <streams/interface_stream.h>
+#include <streams/file_stream.h>
+#include <streams/rzip_stream.h>
+#include <retro_miscellaneous.h>
+
+#define FILE_TRANSFER_CHUNK_SIZE 4096
+
+enum rzip_action_type
+{
+       RZIP_ACTION_QUERY = 0,
+       RZIP_ACTION_COMPRESS,
+       RZIP_ACTION_EXTRACT
+};
+
+static void rand_str(char *dst, size_t len)
+{
+   char charset[] = "0123456789"
+         "abcdefghijklmnopqrstuvwxyz"
+         "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+   while (len-- > 0)
+   {
+      size_t i = (double)rand() / RAND_MAX * (sizeof(charset) - 1);
+      *dst++   = charset[i];
+   }
+   *dst = '\0';
+}
+
+int main(int argc, char *argv[])
+{
+   char in_file_path[PATH_MAX_LENGTH];
+   char out_file_path[PATH_MAX_LENGTH];
+   enum rzip_action_type action = RZIP_ACTION_QUERY;
+   intfstream_t *in_file        = NULL;
+   intfstream_t *out_file       = NULL;
+   int64_t in_file_size         = 0;
+   int64_t in_file_raw_size     = 0;
+   int64_t out_file_size        = 0;
+   int64_t file_size_diff       = 0;
+   int64_t total_data_read      = 0;
+   bool in_file_compressed      = false;
+   bool valid_args              = false;
+   bool in_place                = false;
+   int ret                      = 1;
+
+   in_file_path[0]  = '\0';
+   out_file_path[0] = '\0';
+
+   /* Parse arguments */
+   if ((argc > 1) && !string_is_empty(argv[1]))
+   {
+      valid_args = true;
+
+      if (string_is_equal(argv[1], "i"))
+         action = RZIP_ACTION_QUERY;
+      else if (string_is_equal(argv[1], "a"))
+         action = RZIP_ACTION_COMPRESS;
+      else if (string_is_equal(argv[1], "x"))
+         action = RZIP_ACTION_EXTRACT;
+      else
+         valid_args = false;
+   }
+
+   /* Get input file path */
+   if (valid_args && (argc > 2) && !string_is_empty(argv[2]))
+   {
+      strlcpy(in_file_path, argv[2], sizeof(in_file_path));
+      path_resolve_realpath(in_file_path, sizeof(in_file_path), true);
+      valid_args = valid_args && !string_is_empty(in_file_path);
+   }
+   else
+      valid_args = false;
+
+   /* Ensure arguments are valid */
+   if (!valid_args)
+   {
+      fprintf(stderr, "Usage:\n");
+      fprintf(stderr, "- Query file status: %s i <input file>\n", argv[0]);
+      fprintf(stderr, "- Compress file:     %s a <input file> <output file (optional)>\n", argv[0]);
+      fprintf(stderr, "- Extract file:      %s x <input file> <output file (optional)>\n", argv[0]);
+      fprintf(stderr, "Omitting <output file> will overwrite <input file>\n");
+      goto end;
+   }
+
+   /* Ensure that input file exists */
+   if (!path_is_valid(in_file_path))
+   {
+      fprintf(stderr, "ERROR: Input file does not exist: %s\n", in_file_path);
+      goto end;
+   }
+
+   /* Get output file path, if specified */
+   if ((argc > 3) && !string_is_empty(argv[3]))
+   {
+      strlcpy(out_file_path, argv[3], sizeof(out_file_path));
+      path_resolve_realpath(out_file_path, sizeof(out_file_path), true);
+   }
+
+   /* If we are compressing/extracting and an
+    * output file was not specified, generate a
+    * temporary output file path */
+   if ((action != RZIP_ACTION_QUERY) &&
+       string_is_empty(out_file_path))
+   {
+      const char *in_file_name = path_basename(in_file_path);
+      char in_file_dir[PATH_MAX_LENGTH];
+
+      in_file_dir[0] = '\0';
+
+      fill_pathname_parent_dir(in_file_dir, in_file_path, sizeof(in_file_dir));
+
+      if (string_is_empty(in_file_name))
+      {
+         fprintf(stderr, "ERROR: Invalid input file: %s\n", in_file_path);
+         goto end;
+      }
+
+      srand((unsigned int)time(NULL));
+
+      for (;;)
+      {
+         char tmp_str[10] = {0};
+
+         /* Generate 'random' file name */
+         rand_str(tmp_str, sizeof(tmp_str) - 1);
+         tmp_str[0] = '.';
+
+         if (!string_is_empty(in_file_dir))
+            fill_pathname_join_special(out_file_path, in_file_dir,
+                  tmp_str, sizeof(out_file_path));
+         else
+            strlcpy(out_file_path, tmp_str, sizeof(out_file_path));
+
+         strlcat(out_file_path, ".", sizeof(out_file_path));
+         strlcat(out_file_path, in_file_name, sizeof(out_file_path));
+         path_resolve_realpath(out_file_path, sizeof(out_file_path), true);
+
+         if (!path_is_valid(out_file_path))
+            break;
+      }
+
+      in_place = true;
+   }
+
+   /* Ensure that input and output files
+    * are different */
+   if (string_is_equal(in_file_path, out_file_path))
+   {
+      fprintf(stderr, "ERROR: Input and output are the same file: %s\n", in_file_path);
+      goto end;
+   }
+
+   /* Get input file size */
+   in_file_size = (int64_t)path_get_size(in_file_path);
+
+   if (in_file_size < 1)
+   {
+      fprintf(stderr, "ERROR: Input file is empty: %s\n", in_file_path);
+      goto end;
+   }
+
+   /* Open input file
+    * > Always use RZIP interface */
+   in_file = intfstream_open_rzip_file(
+         in_file_path, RETRO_VFS_FILE_ACCESS_READ);
+
+   if (!in_file)
+   {
+      fprintf(stderr, "ERROR: Failed to open input file: %s\n", in_file_path);
+      goto end;
+   }
+
+   /* Get input file compression status */
+   in_file_compressed = intfstream_is_compressed(in_file);
+
+   /* Get raw (uncompressed) input file size */
+   in_file_raw_size   = intfstream_get_size(in_file);
+
+   /* If this is a query operation, just
+    * print current state */
+   if (action == RZIP_ACTION_QUERY)
+   {
+      printf("%s: %s\n",
+            in_file_compressed ? "File is in RZIP format" : "File is NOT in RZIP format",
+            in_file_path);
+      printf("   Size on disk:      %" PRIi64 " bytes\n", in_file_size);
+      if (in_file_compressed)
+         printf("   Uncompressed size: %" PRIi64 " bytes\n", in_file_raw_size);
+      goto end;
+   }
+
+   /* Check whether file is already in the
+    * requested state */
+   if ((in_file_compressed  && (action == RZIP_ACTION_COMPRESS)) ||
+       (!in_file_compressed && (action == RZIP_ACTION_EXTRACT)))
+   {
+      printf("Input file is %s: %s\n",
+            in_file_compressed ?
+                  "already in RZIP format - cannot compress" :
+                        "not in RZIP format - cannot extract",
+            in_file_path);
+      goto end;
+   }
+
+   /* Check whether output file already exists */
+   if (path_is_valid(out_file_path))
+   {
+      char reply[8];
+
+      reply[0] = '\0';
+
+      printf("WARNING: Output file already exists: %s\n", out_file_path);
+      printf("         Overwrite? [Y/n]: ");
+      fgets(reply, sizeof(reply), stdin);
+      if (reply[0] != 'Y')
+         goto end;
+   }
+
+   /* Open output file */
+   if (in_file_compressed)
+      out_file = intfstream_open_file(
+            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE,
+            RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   else
+      out_file = intfstream_open_rzip_file(
+            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE);
+
+   if (!out_file)
+   {
+      fprintf(stderr, "ERROR: Failed to open output file: %s\n", out_file_path);
+      goto end;
+   }
+
+   /* Start file transfer */
+   printf("%s file\n", in_file_compressed ? "Extracting" : "Compressing");
+   printf("   From: %s\n", in_file_path);
+   printf("   To:   %s\n", in_place ? in_file_path : out_file_path);
+
+   for (;;)
+   {
+      int64_t data_written = 0;
+      uint8_t buffer[FILE_TRANSFER_CHUNK_SIZE];
+      /* Read a single chunk from input file */
+      int64_t data_read    = intfstream_read(
+            in_file, buffer, sizeof(buffer));
+
+      if (data_read < 0)
+      {
+         fprintf(stderr, "ERROR: Failed to read from input file: %s\n", in_file_path);
+         goto end;
+      }
+
+      total_data_read += data_read;
+
+      /* Check whether we have reached the end of the file */
+      if (data_read == 0)
+      {
+         /* Close files */
+         intfstream_flush(out_file);
+         intfstream_close(out_file);
+         free(out_file);
+         out_file = NULL;
+
+         intfstream_close(in_file);
+         free(in_file);
+         in_file = NULL;
+
+         break;
+      }
+
+      /* Write chunk to backup file */
+      data_written = intfstream_write(out_file, buffer, data_read);
+
+      if (data_written != data_read)
+      {
+         fprintf(stderr, "ERROR: Failed to write to output file: %s\n", out_file_path);
+         goto end;
+      }
+
+      /* Update progress */
+      printf("\rProgress: %" PRIi64 " %%", total_data_read * 100 / in_file_raw_size);
+      fflush(stdout);
+   }
+   printf("\rProgress: 100 %%\n");
+
+   /* Display final status 'report' */
+   printf("%s complete:\n", in_file_compressed ? "Extraction" : "Compression");
+
+   out_file_size  = (int64_t)path_get_size(out_file_path);
+   file_size_diff = (in_file_size > out_file_size) ?
+         (in_file_size - out_file_size) :
+               (out_file_size - in_file_size);
+
+   printf("   %" PRIi64 " -> %" PRIi64 " bytes [%" PRIi64 " %% %s]\n",
+         in_file_size, out_file_size,
+               file_size_diff * 100 / in_file_size,
+               (out_file_size >= in_file_size) ?
+                     "increase" : "decrease");
+
+   /* If this was an in-place operation,
+    * replace input file with output file */
+   if (in_place)
+   {
+      filestream_delete(in_file_path);
+      if (filestream_rename(out_file_path, in_file_path))
+      {
+         fprintf(stderr, "ERROR: Failed to rename temporary file\n");
+         fprintf(stderr, "   From: %s\n", out_file_path);
+         fprintf(stderr, "   To:   %s\n", in_file_path);
+         goto end;
+      }
+   }
+
+   ret = 0;
+
+end:
+   if (in_file)
+   {
+      intfstream_close(in_file);
+      free(in_file);
+   }
+
+   if (out_file)
+   {
+      intfstream_close(out_file);
+      free(out_file);
+   }
+
+   return ret;
+}
diff --git a/deps/libretro-common/samples/utils/Makefile b/deps/libretro-common/samples/utils/Makefile
new file mode 100644 (file)
index 0000000..f69bc92
--- /dev/null
@@ -0,0 +1,113 @@
+compiler    := gcc
+extra_flags :=
+use_neon    := 0
+release           := release
+EXE_EXT              :=
+
+ifeq ($(platform),)
+platform = unix
+ifeq ($(shell uname -a),)
+   platform = win
+else ifneq ($(findstring MINGW,$(shell uname -a)),)
+   platform = win
+else ifneq ($(findstring Darwin,$(shell uname -a)),)
+   platform = osx
+   arch = intel
+ifeq ($(shell uname -p),powerpc)
+   arch = ppc
+endif
+else ifneq ($(findstring win,$(shell uname -a)),)
+   platform = win
+endif
+endif
+
+ifeq ($(compiler),gcc)
+extra_rules_gcc := $(shell $(compiler) -dumpmachine)
+endif
+
+ifneq (,$(findstring armv7,$(extra_rules_gcc)))
+extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon
+use_neon := 1
+endif
+
+ifneq (,$(findstring hardfloat,$(extra_rules_gcc)))
+extra_flags += -mfloat-abi=hard
+endif
+
+ifeq (release,$(build))
+extra_flags += -O2
+endif
+
+ifeq (debug,$(build))
+extra_flags += -O0 -g
+endif
+
+ldflags :=
+
+EXE_EXT :=
+ifeq ($(platform), unix)
+else ifeq ($(platform), osx)
+compiler := $(CC)
+else
+EXE_EXT = .exe
+endif
+
+PWD_DIR := .
+LIBRETRO_COMM_DIR := ../..
+CORE_DIR := $(LIBRETRO_COMM_DIR)/utils
+
+CC      := $(compiler)
+CXX     := $(subst CC,++,$(compiler))
+flags   := -I$(LIBRETRO_COMM_DIR)/include
+asflags := $(extra_flags)
+LDFLAGS :=
+flags   += -std=c99 -DMD5_BUILD_UTILITY -DSHA1_BUILD_UTILITY
+
+ifeq (1,$(use_neon))
+ASMFLAGS := -INEON/asm
+asflags += -mfpu=neon
+endif
+
+DJB2_OBJS := $(CORE_DIR)/djb2.o
+
+MD5_OBJS  := $(CORE_DIR)/md5.o \
+                                $(PWD_DIR)/md5_test.o
+
+SHA1_OBJS := $(CORE_DIR)/sha1.o \
+                                $(PWD_DIR)/sha1_main.o
+
+CRC32_OBJS := $(PWD_DIR)/crc32.o \
+                                 $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.o \
+                                 $(LIBRETRO_COMM_DIR)/compat/compat_strl.o \
+                                 $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.o \
+                                 $(LIBRETRO_COMM_DIR)/streams/file_stream.o \
+                                 $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.o \
+                            $(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.o
+
+UTILS := djb2$(EXE_EXT) md5$(EXE_EXT) sha1$(EXE_EXT) crc32$(EXE_EXT)
+
+all: $(UTILS)
+
+djb2$(EXE_EXT): $(DJB2_OBJS)
+
+md5$(EXE_EXT): $(MD5_OBJS)
+
+sha1$(EXE_EXT): $(SHA1_OBJS)
+
+crc32$(EXE_EXT): $(CRC32_OBJS)
+
+%.o: %.S
+       $(CC) -c -o $@ $(asflags) $(LDFLAGS)  $(ASMFLAGS)  $<
+
+%.o: %.c
+       $(CC) -c -o $@ $(flags) $<
+
+$(UTILS):
+       $(CC) -o $@ $(ldflags) $(flags) $^
+
+clean:
+       rm -f $(CORE_DIR)/*.o
+       rm -f $(UTILS)
+
+strip:
+       strip -s $(UTILS)
diff --git a/deps/libretro-common/samples/utils/crc32.c b/deps/libretro-common/samples/utils/crc32.c
new file mode 100644 (file)
index 0000000..786fed7
--- /dev/null
@@ -0,0 +1,43 @@
+/* gcc -O3 -o crc32 crc32.c -lz */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <encodings/crc32.h>
+
+int main(int argc, const char* argv[])
+{
+   if (argc != 2 )
+   {
+      fprintf( stderr, "Usage: crc32 <filename>\n" );
+      return 1;
+   }
+
+   FILE *file = fopen(argv[1], "rb");
+
+   if (file)
+   {
+      uint32_t crc = encoding_crc32(0L, NULL, 0 );
+
+      for (;;)
+      {
+         uint8_t buffer[16384];
+
+         int numread = fread((void*)buffer, 1, sizeof(buffer), file);
+
+         if (numread > 0)
+            crc = encoding_crc32( crc, buffer, numread );
+         else
+            break;
+      }
+
+      fclose(file);
+
+      printf("%08x\n", crc);
+      return 0;
+   }
+
+   fprintf(stderr, "Error opening input file: %s\n", strerror(errno));
+   return 1;
+}
diff --git a/deps/libretro-common/samples/utils/md5_test.c b/deps/libretro-common/samples/utils/md5_test.c
new file mode 100644 (file)
index 0000000..3081f57
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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 <solar at openwall.com>
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <lrc_hash.h>
+
+int main (int argc, char *argv[])
+{
+   /* For each command line argument in turn:
+    ** filename          -- prints message digest and name of file
+    */
+   int i;
+   MD5_CTX ctx;
+   FILE* file;
+   size_t numread;
+   char buffer[16384];
+   unsigned char result[16];
+
+   for (i = 1; i < argc; i++)
+   {
+      MD5_Init(&ctx);
+      file = fopen(argv[i], "rb");
+
+      if (file)
+      {
+         do
+         {
+            numread = fread((void*)buffer, 1, sizeof(buffer), file);
+
+            if (numread)
+            {
+               MD5_Update(&ctx,(void*)buffer, numread);
+            }
+         }
+         while (numread);
+
+         fclose(file);
+         MD5_Final(result, &ctx);
+         printf("%02x%02x%02x%02x%02x%02x%02x%02x"
+                                 "%02x%02x%02x%02x%02x%02x%02x%02x %s\n",
+                                 result[ 0 ], result[ 1 ], result[ 2 ], result[ 3 ],
+                result[ 4 ], result[ 5 ], result[ 6 ], result[ 7 ],
+                result[ 8 ], result[ 9 ], result[ 10 ], result[ 11 ],
+                result[ 12 ], result[ 13 ], result[ 14 ], result[ 15 ],
+                argv[i]);
+      }
+   }
+
+   return 0;
+}
diff --git a/deps/libretro-common/samples/utils/sha1_main.c b/deps/libretro-common/samples/utils/sha1_main.c
new file mode 100644 (file)
index 0000000..58745fa
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *  sha.cpp
+ *
+ *  Copyright (C) 1998, 2009
+ *  Paul E. Jones <paulej@packetizer.com>
+ *  All Rights Reserved
+ *
+ *****************************************************************************
+ *  $Id: sha.c 12 2009-06-22 19:34:25Z paulej $
+ *****************************************************************************
+ *
+ *  Description:
+ *      This utility will display the message digest (fingerprint) for
+ *      the specified file(s).
+ *
+ *  Portability Issues:
+ *      None.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef _WIN32
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include <string/stdstring.h>
+/*#include "sha1.h"*/
+
+/*
+ *  Function prototype
+ */
+void usage(void);
+
+/*
+ *  main
+ *
+ *  Description:
+ *      This is the entry point for the program
+ *
+ *  Parameters:
+ *      argc: [in]
+ *          This is the count of arguments in the argv array
+ *      argv: [in]
+ *          This is an array of filenames for which to compute message
+ *          digests
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *
+ */
+typedef struct SHA1Context
+{
+   unsigned Message_Digest[5]; /* Message Digest (output)          */
+
+   unsigned Length_Low;        /* Message length in bits           */
+   unsigned Length_High;       /* Message length in bits           */
+
+   unsigned char Message_Block[64]; /* 512-bit message blocks      */
+   int Message_Block_Index;    /* Index into message block array   */
+
+   int Computed;               /* Is the digest computed?          */
+   int Corrupted;              /* Is the message digest corruped?  */
+} SHA1Context;
+
+int main(int argc, char *argv[])
+{
+   struct SHA1Context sha;         /* SHA-1 context                 */
+   FILE        *fp;                /* File pointer for reading files*/
+   char        c;                  /* Character read from file      */
+   int         i;                  /* Counter                       */
+   int         reading_stdin;      /* Are we reading standard in?   */
+   int         read_stdin = 0;     /* Have we read stdin?           */
+
+   /*
+    *  Check the program arguments and print usage information if -?
+    *  or --help is passed as the first argument.
+    */
+   if (argc > 1 && (string_is_equal(argv[1],"-?") ||
+            string_is_equal(argv[1],"--help")))
+   {
+      usage();
+      return 1;
+   }
+
+   /*
+    *  For each filename passed in on the command line, calculate the
+    *  SHA-1 value and display it.
+    */
+   for (i = 0; i < argc; i++)
+   {
+      /*
+       *  We start the counter at 0 to guarantee entry into the for
+       *  loop. So if 'i' is zero, we will increment it now.  If there
+       *  is no argv[1], we will use STDIN below.
+       */
+      if (i == 0)
+         i++;
+
+      if (argc == 1 || string_is_equal(argv[i],"-"))
+      {
+#ifdef WIN32
+         setmode(fileno(stdin), _O_BINARY);
+#endif
+         fp = stdin;
+         reading_stdin = 1;
+      }
+      else
+      {
+         if (!(fp = fopen(argv[i],"rb")))
+         {
+            fprintf(stderr,
+                  "sha: unable to open file %s\n",
+                  argv[i]);
+            return 2;
+         }
+         reading_stdin = 0;
+      }
+
+      /*
+       *  We do not want to read STDIN multiple times
+       */
+      if (reading_stdin)
+      {
+         if (read_stdin)
+            continue;
+
+         read_stdin = 1;
+      }
+
+      /*
+       *  Reset the SHA-1 context and process input
+       */
+      SHA1Reset(&sha);
+
+      c = fgetc(fp);
+      while(!feof(fp))
+      {
+         SHA1Input(&sha, &c, 1);
+         c = fgetc(fp);
+      }
+
+      if (!reading_stdin)
+         fclose(fp);
+
+      if (!SHA1Result(&sha))
+      {
+         fprintf(stderr,
+               "sha: could not compute message digest for %s\n",
+               reading_stdin?"STDIN":argv[i]);
+      }
+      else
+      {
+         printf( "%08X %08X %08X %08X %08X - %s\n",
+               sha.Message_Digest[0],
+               sha.Message_Digest[1],
+               sha.Message_Digest[2],
+               sha.Message_Digest[3],
+               sha.Message_Digest[4],
+               reading_stdin?"STDIN":argv[i]);
+      }
+   }
+
+   return 0;
+}
+
+/*
+ *  usage
+ *
+ *  Description:
+ *      This function will display program usage information to the
+ *      user.
+ *
+ *  Parameters:
+ *      None.
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *
+ */
+void usage(void)
+{
+   printf("usage: sha <file> [<file> ...]\n");
+   printf("\tThis program will display the message digest\n");
+   printf("\tfor files using the Secure Hashing Algorithm (SHA-1).\n");
+}
diff --git a/deps/libretro-common/streams/chd_stream.c b/deps/libretro-common/streams/chd_stream.c
new file mode 100644 (file)
index 0000000..daa718f
--- /dev/null
@@ -0,0 +1,470 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (chd_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <boolean.h>
+
+#include <streams/chd_stream.h>
+#include <retro_endianness.h>
+#include <libchdr/chd.h>
+#include <string/stdstring.h>
+
+#define SECTOR_SIZE 2352
+#define SUBCODE_SIZE 96
+#define TRACK_PAD 4
+
+struct chdstream
+{
+   chd_file *chd;
+   /* Loaded hunk */
+   uint8_t *hunkmem;
+   /* Byte offset where track data starts (after pregap) */
+   size_t track_start;
+   /* Byte offset where track data ends */
+   size_t track_end;
+   /* Byte offset of read cursor */
+   size_t offset;
+   /* Loaded hunk number */
+   int32_t hunknum;
+   /* Size of frame taken from each hunk */
+   uint32_t frame_size;
+   /* Offset of data within frame */
+   uint32_t frame_offset;
+   /* Number of frames per hunk */
+   uint32_t frames_per_hunk;
+   /* First frame of track in chd */
+   uint32_t track_frame;
+   /* Should we swap bytes? */
+   bool swab;
+};
+
+typedef struct metadata
+{
+   uint32_t frame_offset;
+   uint32_t frames;
+   uint32_t pad;
+   uint32_t extra;
+   uint32_t pregap;
+   uint32_t postgap;
+   uint32_t track;
+   char type[64];
+   char subtype[32];
+   char pgtype[32];
+   char pgsub[32];
+} metadata_t;
+
+static uint32_t padding_frames(uint32_t frames)
+{
+   return ((frames + TRACK_PAD - 1) & ~(TRACK_PAD - 1)) - frames;
+}
+
+static bool
+chdstream_get_meta(chd_file *chd, int idx, metadata_t *md)
+{
+   char meta[256];
+   uint32_t meta_size = 0;
+   chd_error err;
+
+   meta[0] = '\0';
+
+   memset(md, 0, sizeof(*md));
+
+   err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, idx, meta,
+         sizeof(meta), &meta_size, NULL, NULL);
+
+   if (err == CHDERR_NONE)
+   {
+      sscanf(meta, CDROM_TRACK_METADATA2_FORMAT,
+            &md->track, md->type,
+            md->subtype, &md->frames, &md->pregap,
+            md->pgtype, md->pgsub,
+            &md->postgap);
+      md->extra = padding_frames(md->frames);
+      return true;
+   }
+
+   err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, idx, meta,
+         sizeof(meta), &meta_size, NULL, NULL);
+
+   if (err == CHDERR_NONE)
+   {
+      sscanf(meta, CDROM_TRACK_METADATA_FORMAT, &md->track, md->type,
+             md->subtype, &md->frames);
+      md->extra = padding_frames(md->frames);
+      return true;
+   }
+
+   err = chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, idx, meta,
+         sizeof(meta), &meta_size, NULL, NULL);
+
+   if (err == CHDERR_NONE)
+   {
+      sscanf(meta, GDROM_TRACK_METADATA_FORMAT, &md->track, md->type,
+             md->subtype, &md->frames, &md->pad, &md->pregap, md->pgtype,
+             md->pgsub, &md->postgap);
+      md->extra = padding_frames(md->frames);
+      return true;
+   }
+
+   return false;
+}
+
+static bool
+chdstream_find_track_number(chd_file *fd, int32_t track, metadata_t *meta)
+{
+   uint32_t i;
+   uint32_t frame_offset = 0;
+
+   for (i = 0; true; ++i)
+   {
+      if (!chdstream_get_meta(fd, i, meta))
+         return false;
+
+      if (track == (int)meta->track)
+      {
+         meta->frame_offset = frame_offset;
+         return true;
+      }
+
+      frame_offset += meta->frames + meta->extra;
+   }
+}
+
+static bool
+chdstream_find_special_track(chd_file *fd, int32_t track, metadata_t *meta)
+{
+   int32_t i;
+   metadata_t iter;
+   int32_t largest_track = 0;
+   uint32_t largest_size = 0;
+
+   for (i = 1; true; ++i)
+   {
+      if (!chdstream_find_track_number(fd, i, &iter))
+      {
+         if (track == CHDSTREAM_TRACK_LAST && i > 1)
+            return chdstream_find_track_number(fd, i - 1, meta);
+
+         if (track == CHDSTREAM_TRACK_PRIMARY && largest_track != 0)
+            return chdstream_find_track_number(fd, largest_track, meta);
+
+         return false;
+      }
+
+      switch (track)
+      {
+         case CHDSTREAM_TRACK_FIRST_DATA:
+            if (strcmp(iter.type, "AUDIO"))
+            {
+               *meta = iter;
+               return true;
+            }
+            break;
+         case CHDSTREAM_TRACK_PRIMARY:
+            if (strcmp(iter.type, "AUDIO") && iter.frames > largest_size)
+            {
+               largest_size  = iter.frames;
+               largest_track = iter.track;
+            }
+            break;
+         default:
+            break;
+      }
+   }
+}
+
+static bool
+chdstream_find_track(chd_file *fd, int32_t track, metadata_t *meta)
+{
+   if (track < 0)
+      return chdstream_find_special_track(fd, track, meta);
+   return chdstream_find_track_number(fd, track, meta);
+}
+
+chdstream_t *chdstream_open(const char *path, int32_t track)
+{
+   metadata_t meta;
+   uint32_t pregap         = 0;
+   uint8_t *hunkmem        = NULL;
+   const chd_header *hd    = NULL;
+   chdstream_t *stream     = NULL;
+   chd_file *chd           = NULL;
+   chd_error err           = chd_open(path, CHD_OPEN_READ, NULL, &chd);
+
+   if (err != CHDERR_NONE)
+      return NULL;
+
+   if (!chdstream_find_track(chd, track, &meta))
+      goto error;
+
+   stream                  = (chdstream_t*)malloc(sizeof(*stream));
+   if (!stream)
+      goto error;
+
+   stream->chd             = NULL;
+   stream->swab            = false;
+   stream->frame_size      = 0;
+   stream->frame_offset    = 0;
+   stream->frames_per_hunk = 0;
+   stream->track_frame     = 0;
+   stream->track_start     = 0;
+   stream->track_end       = 0;
+   stream->offset          = 0;
+   stream->hunkmem         = NULL;
+   stream->hunknum         = -1;
+
+   hd                      = chd_get_header(chd);
+   hunkmem                 = (uint8_t*)malloc(hd->hunkbytes);
+   if (!hunkmem)
+      goto error;
+
+   stream->hunkmem         = hunkmem;
+
+   if (string_is_equal(meta.type, "MODE1_RAW"))
+      stream->frame_size   = SECTOR_SIZE;
+   else if (string_is_equal(meta.type, "MODE2_RAW"))
+      stream->frame_size   = SECTOR_SIZE;
+   else if (string_is_equal(meta.type, "AUDIO"))
+   {
+      stream->frame_size   = SECTOR_SIZE;
+      stream->swab         = true;
+   }
+   else
+      stream->frame_size   = hd->unitbytes;
+
+   /* Only include pregap data if it was in the track file */
+   if (meta.pgtype[0] != 'V')
+      pregap               = meta.pregap;
+
+   stream->chd             = chd;
+   stream->frames_per_hunk = hd->hunkbytes / hd->unitbytes;
+   stream->track_frame     = meta.frame_offset;
+   stream->track_start     = (size_t)pregap * stream->frame_size;
+   stream->track_end       = stream->track_start + 
+                             (size_t)meta.frames * stream->frame_size;
+
+   return stream;
+
+error:
+
+   chdstream_close(stream);
+
+   if (chd)
+      chd_close(chd);
+
+   return NULL;
+}
+
+void chdstream_close(chdstream_t *stream)
+{
+   if (!stream)
+      return;
+
+   if (stream->hunkmem)
+      free(stream->hunkmem);
+   if (stream->chd)
+      chd_close(stream->chd);
+   free(stream);
+}
+
+static bool
+chdstream_load_hunk(chdstream_t *stream, uint32_t hunknum)
+{
+   uint16_t *array;
+
+   if ((int)hunknum == stream->hunknum)
+      return true;
+
+   if (chd_read(stream->chd, hunknum, stream->hunkmem) != CHDERR_NONE)
+      return false;
+
+   if (stream->swab)
+   {
+      uint32_t i;
+      uint32_t count = chd_get_header(stream->chd)->hunkbytes / 2;
+      array          = (uint16_t*)stream->hunkmem;
+      for (i = 0; i < count; ++i)
+         array[i] = SWAP16(array[i]);
+   }
+
+   stream->hunknum = hunknum;
+   return true;
+}
+
+ssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes)
+{
+   size_t end;
+   size_t data_offset   = 0;
+   const chd_header *hd = chd_get_header(stream->chd);
+   uint8_t         *out = (uint8_t*)data;
+
+   if (stream->track_end - stream->offset < bytes)
+      bytes             = stream->track_end - stream->offset;
+
+   end                  = stream->offset + bytes;
+
+   while (stream->offset < end)
+   {
+      uint32_t frame_offset = stream->offset % stream->frame_size;
+      uint32_t amount       = stream->frame_size - frame_offset;
+
+      if (amount > end - stream->offset)
+         amount = (uint32_t)(end - stream->offset);
+
+      /* In pregap */
+      if (stream->offset < stream->track_start)
+         memset(out + data_offset, 0, amount);
+      else
+      {
+         uint32_t chd_frame   = (uint32_t)(stream->track_frame +
+            (stream->offset - stream->track_start) / stream->frame_size);
+         uint32_t hunk        = chd_frame / stream->frames_per_hunk;
+         uint32_t hunk_offset = (chd_frame % stream->frames_per_hunk) 
+            * hd->unitbytes;
+
+         if (!chdstream_load_hunk(stream, hunk))
+            return -1;
+
+         memcpy(out + data_offset,
+                stream->hunkmem + frame_offset
+                + hunk_offset + stream->frame_offset, amount);
+      }
+
+      data_offset    += amount;
+      stream->offset += amount;
+   }
+
+   return bytes;
+}
+
+int chdstream_getc(chdstream_t *stream)
+{
+   char c = 0;
+
+   if (chdstream_read(stream, &c, sizeof(c) != sizeof(c)))
+      return EOF;
+
+   return c;
+}
+
+char *chdstream_gets(chdstream_t *stream, char *buffer, size_t len)
+{
+   int c;
+
+   size_t offset = 0;
+
+   while (offset < len && (c = chdstream_getc(stream)) != EOF)
+      buffer[offset++] = c;
+
+   if (offset < len)
+      buffer[offset]   = '\0';
+
+   return buffer;
+}
+
+uint64_t chdstream_tell(chdstream_t *stream)
+{
+   return stream->offset;
+}
+
+void chdstream_rewind(chdstream_t *stream)
+{
+   stream->offset = 0;
+}
+
+int64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence)
+{
+   int64_t new_offset;
+
+   switch (whence)
+   {
+      case SEEK_SET:
+         new_offset = offset;
+         break;
+      case SEEK_CUR:
+         new_offset = stream->offset + offset;
+         break;
+      case SEEK_END:
+         new_offset = stream->track_end + offset;
+         break;
+      default:
+         return -1;
+   }
+
+   if (new_offset < 0)
+      return -1;
+
+   if ((size_t)new_offset > stream->track_end)
+      new_offset = stream->track_end;
+
+   stream->offset = new_offset;
+   return 0;
+}
+
+ssize_t chdstream_get_size(chdstream_t *stream)
+{
+   return stream->track_end - stream->track_start;
+}
+
+uint32_t chdstream_get_track_start(chdstream_t *stream)
+{
+   uint32_t i;
+   metadata_t meta;
+   uint32_t frame_offset = 0;
+
+   for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i)
+   {
+      if (stream->track_frame == frame_offset)
+         return meta.pregap * stream->frame_size;
+
+      frame_offset += meta.frames + meta.extra;
+   }
+
+   return 0;
+}
+
+uint32_t chdstream_get_frame_size(chdstream_t *stream)
+{
+   return stream->frame_size;
+}
+
+uint32_t chdstream_get_first_track_sector(chdstream_t* stream)
+{
+   uint32_t i;
+   metadata_t meta;
+   uint32_t frame_offset = 0;
+   uint32_t sector_offset = 0;
+
+   for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i)
+   {
+      if (stream->track_frame == frame_offset)
+         return sector_offset;
+
+      sector_offset += meta.frames;
+      frame_offset += meta.frames + meta.extra;
+   }
+
+   return 0;
+}
diff --git a/deps/libretro-common/streams/file_stream.c b/deps/libretro-common/streams/file_stream.c
new file mode 100644 (file)
index 0000000..befb31c
--- /dev/null
@@ -0,0 +1,659 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+
+#include <string/stdstring.h>
+#include <streams/file_stream.h>
+#define VFS_FRONTEND
+#include <vfs/vfs_implementation.h>
+
+#define VFS_ERROR_RETURN_VALUE -1
+
+struct RFILE
+{
+   struct retro_vfs_file_handle *hfile;
+       bool error_flag;
+};
+
+static retro_vfs_get_path_t filestream_get_path_cb = NULL;
+static retro_vfs_open_t filestream_open_cb         = NULL;
+static retro_vfs_close_t filestream_close_cb       = NULL;
+static retro_vfs_size_t filestream_size_cb         = NULL;
+static retro_vfs_truncate_t filestream_truncate_cb = NULL;
+static retro_vfs_tell_t filestream_tell_cb         = NULL;
+static retro_vfs_seek_t filestream_seek_cb         = NULL;
+static retro_vfs_read_t filestream_read_cb         = NULL;
+static retro_vfs_write_t filestream_write_cb       = NULL;
+static retro_vfs_flush_t filestream_flush_cb       = NULL;
+static retro_vfs_remove_t filestream_remove_cb     = NULL;
+static retro_vfs_rename_t filestream_rename_cb     = NULL;
+
+/* VFS Initialization */
+
+void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
+{
+   const struct retro_vfs_interface *
+      vfs_iface           = vfs_info->iface;
+
+   filestream_get_path_cb = NULL;
+   filestream_open_cb     = NULL;
+   filestream_close_cb    = NULL;
+   filestream_tell_cb     = NULL;
+   filestream_size_cb     = NULL;
+   filestream_truncate_cb = NULL;
+   filestream_seek_cb     = NULL;
+   filestream_read_cb     = NULL;
+   filestream_write_cb    = NULL;
+   filestream_flush_cb    = NULL;
+   filestream_remove_cb   = NULL;
+   filestream_rename_cb   = NULL;
+
+   if (
+             (vfs_info->required_interface_version < 
+             FILESTREAM_REQUIRED_VFS_VERSION)
+         || !vfs_iface)
+      return;
+
+   filestream_get_path_cb = vfs_iface->get_path;
+   filestream_open_cb     = vfs_iface->open;
+   filestream_close_cb    = vfs_iface->close;
+   filestream_size_cb     = vfs_iface->size;
+   filestream_truncate_cb = vfs_iface->truncate;
+   filestream_tell_cb     = vfs_iface->tell;
+   filestream_seek_cb     = vfs_iface->seek;
+   filestream_read_cb     = vfs_iface->read;
+   filestream_write_cb    = vfs_iface->write;
+   filestream_flush_cb    = vfs_iface->flush;
+   filestream_remove_cb   = vfs_iface->remove;
+   filestream_rename_cb   = vfs_iface->rename;
+}
+
+/* Callback wrappers */
+bool filestream_exists(const char *path)
+{
+   RFILE *dummy           = NULL;
+
+   if (!path || !*path)
+      return false;
+   if (!(dummy = filestream_open(
+         path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE)))
+      return false;
+
+   if (filestream_close(dummy) != 0)
+      free(dummy);
+
+   dummy = NULL;
+   return true;
+}
+
+int64_t filestream_get_size(RFILE *stream)
+{
+   int64_t output;
+
+   if (filestream_size_cb)
+      output = filestream_size_cb(stream->hfile);
+   else
+      output = retro_vfs_file_size_impl(
+            (libretro_vfs_implementation_file*)stream->hfile);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int64_t filestream_truncate(RFILE *stream, int64_t length)
+{
+   int64_t output;
+
+   if (filestream_truncate_cb)
+      output = filestream_truncate_cb(stream->hfile, length);
+   else
+      output = retro_vfs_file_truncate_impl(
+            (libretro_vfs_implementation_file*)stream->hfile, length);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+/**
+ * filestream_open:
+ * @path               : path to file
+ * @mode               : file mode to use when opening (read/write)
+ * @hints              :
+ *
+ * Opens a file for reading or writing, depending on the requested mode.
+ * @return A pointer to an RFILE if opened successfully, otherwise NULL.
+ **/
+RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
+{
+   struct retro_vfs_file_handle  *fp = NULL;
+   RFILE* output                     = NULL;
+
+   if (filestream_open_cb)
+      fp = (struct retro_vfs_file_handle*)
+         filestream_open_cb(path, mode, hints);
+   else
+      fp = (struct retro_vfs_file_handle*)
+         retro_vfs_file_open_impl(path, mode, hints);
+
+   if (!fp)
+      return NULL;
+
+   output             = (RFILE*)malloc(sizeof(RFILE));
+   output->error_flag = false;
+   output->hfile      = fp;
+   return output;
+}
+
+char* filestream_gets(RFILE *stream, char *s, size_t len)
+{
+   int c   = 0;
+   char *p = s;
+   if (!stream)
+      return NULL;
+
+   /* get max bytes or up to a newline */
+
+   for (len--; len > 0; len--)
+   {
+      if ((c = filestream_getc(stream)) == EOF)
+         break;
+      *p++ = c;
+      if (c == '\n')
+         break;
+   }
+   *p = 0;
+
+   if (p == s && c == EOF)
+      return NULL;
+   return (s);
+}
+
+int filestream_getc(RFILE *stream)
+{
+   char c = 0;
+   if (stream && filestream_read(stream, &c, 1) == 1)
+      return (int)(unsigned char)c;
+   return EOF;
+}
+
+int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
+{
+   char buf[4096];
+   char subfmt[64];
+   va_list args_copy;
+   const char *bufiter  = buf;
+   int        ret       = 0;
+   int64_t startpos     = filestream_tell(stream);
+   int64_t maxlen       = filestream_read(stream, buf, sizeof(buf)-1);
+
+   if (maxlen <= 0)
+      return EOF;
+
+   buf[maxlen] = '\0';
+
+   /* Have to copy the input va_list here
+    * > Calling va_arg() on 'args' directly would
+    *   cause the va_list to have an indeterminate value
+    *   in the function calling filestream_vscanf(),
+    *   leading to unexpected behaviour */
+#ifdef __va_copy
+   __va_copy(args_copy, *args);
+#else
+   va_copy(args_copy, *args);
+#endif
+
+   while (*format)
+   {
+      if (*format == '%')
+      {
+         int sublen;
+         char* subfmtiter = subfmt;
+         bool asterisk    = false;
+
+         *subfmtiter++    = *format++; /* '%' */
+
+         /* %[*][width][length]specifier */
+
+         if (*format == '*')
+         {
+            asterisk      = true;
+            *subfmtiter++ = *format++;
+         }
+
+         while (ISDIGIT((unsigned char)*format))
+            *subfmtiter++ = *format++; /* width */
+
+         /* length */
+         if (*format == 'h' || *format == 'l')
+         {
+            if (format[1] == format[0])
+               *subfmtiter++ = *format++;
+            *subfmtiter++    = *format++;
+         }
+         else if (
+               *format == 'j' || 
+               *format == 'z' || 
+               *format == 't' || 
+               *format == 'L')
+         {
+            *subfmtiter++ = *format++;
+         }
+
+         /* specifier - always a single character (except ]) */
+         if (*format == '[')
+         {
+            while (*format != ']')
+               *subfmtiter++ = *format++;
+            *subfmtiter++    = *format++;
+         }
+         else
+            *subfmtiter++    = *format++;
+
+         *subfmtiter++       = '%';
+         *subfmtiter++       = 'n';
+         *subfmtiter++       = '\0';
+
+         if (sizeof(void*) != sizeof(long*))
+            abort(); /* all pointers must have the same size */
+
+         if (asterisk)
+         {
+            int v = sscanf(bufiter, subfmt, &sublen);
+            if (v == EOF)
+               return EOF;
+            if (v != 0)
+               break;
+         }
+         else
+         {
+            int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &sublen);
+            if (v == EOF)
+               return EOF;
+            if (v != 1)
+               break;
+         }
+
+         ret++;
+         bufiter += sublen;
+      }
+      else if (isspace((unsigned char)*format))
+      {
+         while (isspace((unsigned char)*bufiter))
+            bufiter++;
+         format++;
+      }
+      else
+      {
+         if (*bufiter != *format)
+            break;
+         bufiter++;
+         format++;
+      }
+   }
+
+   va_end(args_copy);
+   filestream_seek(stream, startpos + (bufiter - buf),
+         RETRO_VFS_SEEK_POSITION_START);
+
+   return ret;
+}
+
+int filestream_scanf(RFILE *stream, const char* format, ...)
+{
+   int result;
+   va_list vl;
+   va_start(vl, format);
+   result = filestream_vscanf(stream, format, &vl);
+   va_end(vl);
+   return result;
+}
+
+int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
+{
+   int64_t output;
+
+   if (filestream_seek_cb)
+      output = filestream_seek_cb(stream->hfile, offset, seek_position);
+   else
+      output = retro_vfs_file_seek_impl(
+            (libretro_vfs_implementation_file*)stream->hfile,
+            offset, seek_position);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int filestream_eof(RFILE *stream)
+{
+   return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
+}
+
+int64_t filestream_tell(RFILE *stream)
+{
+   int64_t output;
+
+   if (filestream_size_cb)
+      output = filestream_tell_cb(stream->hfile);
+   else
+      output = retro_vfs_file_tell_impl(
+            (libretro_vfs_implementation_file*)stream->hfile);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+void filestream_rewind(RFILE *stream)
+{
+   if (!stream)
+      return;
+   filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
+   stream->error_flag = false;
+}
+
+int64_t filestream_read(RFILE *stream, void *s, int64_t len)
+{
+   int64_t output;
+
+   if (filestream_read_cb)
+      output = filestream_read_cb(stream->hfile, s, len);
+   else
+      output = retro_vfs_file_read_impl(
+            (libretro_vfs_implementation_file*)stream->hfile, s, len);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int filestream_flush(RFILE *stream)
+{
+   int output;
+
+   if (filestream_flush_cb)
+      output = filestream_flush_cb(stream->hfile);
+   else
+      output = retro_vfs_file_flush_impl(
+            (libretro_vfs_implementation_file*)stream->hfile);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int filestream_delete(const char *path)
+{
+   if (filestream_remove_cb)
+      return filestream_remove_cb(path);
+
+   return retro_vfs_file_remove_impl(path);
+}
+
+int filestream_rename(const char *old_path, const char *new_path)
+{
+   if (filestream_rename_cb)
+      return filestream_rename_cb(old_path, new_path);
+
+   return retro_vfs_file_rename_impl(old_path, new_path);
+}
+
+const char* filestream_get_path(RFILE *stream)
+{
+   if (filestream_get_path_cb)
+      return filestream_get_path_cb(stream->hfile);
+
+   return retro_vfs_file_get_path_impl(
+         (libretro_vfs_implementation_file*)stream->hfile);
+}
+
+int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
+{
+   int64_t output;
+
+   if (filestream_write_cb)
+      output = filestream_write_cb(stream->hfile, s, len);
+   else
+      output = retro_vfs_file_write_impl(
+            (libretro_vfs_implementation_file*)stream->hfile, s, len);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int filestream_putc(RFILE *stream, int c)
+{
+   char c_char = (char)c;
+   if (!stream)
+      return EOF;
+   return filestream_write(stream, &c_char, 1) == 1 
+      ? (int)(unsigned char)c 
+      : EOF;
+}
+
+int filestream_vprintf(RFILE *stream, const char* format, va_list args)
+{
+   static char buffer[8 * 1024];
+   int64_t num_chars = vsnprintf(buffer, sizeof(buffer),
+         format, args);
+
+   if (num_chars < 0)
+      return -1;
+   else if (num_chars == 0)
+      return 0;
+
+   return (int)filestream_write(stream, buffer, num_chars);
+}
+
+int filestream_printf(RFILE *stream, const char* format, ...)
+{
+   va_list vl;
+   int result;
+   va_start(vl, format);
+   result = filestream_vprintf(stream, format, vl);
+   va_end(vl);
+   return result;
+}
+
+int filestream_error(RFILE *stream)
+{
+   return (stream && stream->error_flag);
+}
+
+int filestream_close(RFILE *stream)
+{
+   int output;
+   struct retro_vfs_file_handle* fp = stream->hfile;
+
+   if (filestream_close_cb)
+      output = filestream_close_cb(fp);
+   else
+      output = retro_vfs_file_close_impl(
+            (libretro_vfs_implementation_file*)fp);
+
+   if (output == 0)
+      free(stream);
+
+   return output;
+}
+
+/**
+ * filestream_read_file:
+ * @path             : path to file.
+ * @buf              : buffer to allocate and read the contents of the
+ *                     file into. Needs to be freed manually.
+ * @len              : optional output integer containing bytes read.
+ *
+ * Read the contents of a file into @buf.
+ *
+ * @return Non-zero on success.
+ */
+int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
+{
+   int64_t ret              = 0;
+   int64_t content_buf_size = 0;
+   void *content_buf        = NULL;
+   RFILE *file              = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+   if (!file)
+   {
+      *buf = NULL;
+      return 0;
+   }
+
+   if ((content_buf_size = filestream_get_size(file)) < 0)
+      goto error;
+
+   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
+      goto error;
+   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
+      goto error;
+
+   if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) <
+         0)
+      goto error;
+
+   if (filestream_close(file) != 0)
+      free(file);
+
+   *buf    = content_buf;
+
+   /* Allow for easy reading of strings to be safe.
+    * Will only work with sane character formatting (Unix). */
+   ((char*)content_buf)[ret] = '\0';
+
+   if (len)
+      *len = ret;
+
+   return 1;
+
+error:
+   if (filestream_close(file) != 0)
+      free(file);
+   if (content_buf)
+      free(content_buf);
+   if (len)
+      *len = -1;
+   *buf = NULL;
+   return 0;
+}
+
+/**
+ * filestream_write_file:
+ * @path             : path to file.
+ * @data             : contents to write to the file.
+ * @size             : size of the contents.
+ *
+ * Writes data to a file.
+ *
+ * @return true on success, otherwise false.
+ **/
+bool filestream_write_file(const char *path, const void *data, int64_t size)
+{
+   int64_t ret   = 0;
+   RFILE *file   = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_WRITE,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   if (!file)
+      return false;
+   ret = filestream_write(file, data, size);
+   if (filestream_close(file) != 0)
+      free(file);
+   return (ret == size);
+}
+
+/**
+ * filestream_getline:
+ *
+ * Returned pointer must be freed by the caller.
+ **/
+char *filestream_getline(RFILE *stream)
+{
+   char *newline_tmp  = NULL;
+   size_t cur_size    = 8;
+   size_t idx         = 0;
+   int in             = 0;
+   char *newline      = (char*)malloc(9);
+
+   if (!stream || !newline)
+   {
+      if (newline)
+         free(newline);
+      return NULL;
+   }
+
+   in = filestream_getc(stream);
+
+   while (in != EOF && in != '\n')
+   {
+      if (idx == cur_size)
+      {
+         cur_size    *= 2;
+
+         if (!(newline_tmp = (char*)realloc(newline, cur_size + 1)))
+         {
+            free(newline);
+            return NULL;
+         }
+
+         newline     = newline_tmp;
+      }
+
+      newline[idx++] = in;
+      in             = filestream_getc(stream);
+   }
+
+   newline[idx]      = '\0';
+   return newline;
+}
+
+libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
+{
+   return (libretro_vfs_implementation_file*)stream->hfile;
+}
diff --git a/deps/libretro-common/streams/file_stream_transforms.c b/deps/libretro-common/streams/file_stream_transforms.c
new file mode 100644 (file)
index 0000000..e94a311
--- /dev/null
@@ -0,0 +1,195 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (file_stream_transforms.c).
+* ---------------------------------------------------------------------------------------
+*
+* 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 <string.h>
+#include <stdarg.h>
+
+#include <libretro.h>
+#include <streams/file_stream.h>
+
+RFILE* rfopen(const char *path, const char *mode)
+{
+   RFILE          *output  = NULL;
+   unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;
+   bool position_to_end    = false;
+
+   if (strstr(mode, "r"))
+   {
+      retro_mode = RETRO_VFS_FILE_ACCESS_READ;
+      if (strstr(mode, "+"))
+      {
+         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
+            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
+      }
+   }
+   else if (strstr(mode, "w"))
+   {
+      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE;
+      if (strstr(mode, "+"))
+         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE;
+   }
+   else if (strstr(mode, "a"))
+   {
+      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE |
+         RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
+      position_to_end = true;
+      if (strstr(mode, "+"))
+      {
+         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
+            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
+      }
+   }
+
+   output = filestream_open(path, retro_mode,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   if (output && position_to_end)
+      filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END);
+
+   return output;
+}
+
+int rfclose(RFILE* stream)
+{
+   if (!stream)
+      return EOF;
+
+   return filestream_close(stream);
+}
+
+int64_t rftell(RFILE* stream)
+{
+   if (!stream)
+      return -1;
+
+   return filestream_tell(stream);
+}
+
+int64_t rfseek(RFILE* stream, int64_t offset, int origin)
+{
+   int seek_position = -1;
+
+   if (!stream)
+      return -1;
+
+   switch (origin)
+   {
+      case SEEK_SET:
+         seek_position = RETRO_VFS_SEEK_POSITION_START;
+         break;
+      case SEEK_CUR:
+         seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
+         break;
+      case SEEK_END:
+         seek_position = RETRO_VFS_SEEK_POSITION_END;
+         break;
+   }
+
+   return filestream_seek(stream, offset, seek_position);
+}
+
+int64_t rfread(void* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream)
+{
+   if (!stream || (elem_size == 0) || (elem_count == 0))
+      return 0;
+
+   return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
+}
+
+char *rfgets(char *buffer, int maxCount, RFILE* stream)
+{
+   if (!stream)
+      return NULL;
+
+   return filestream_gets(stream, buffer, maxCount);
+}
+
+int rfgetc(RFILE* stream)
+{
+   if (!stream)
+      return EOF;
+
+   return filestream_getc(stream);
+}
+
+int64_t rfwrite(void const* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream)
+{
+   if (!stream || (elem_size == 0) || (elem_count == 0))
+      return 0;
+
+   return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);
+}
+
+int rfputc(int character, RFILE * stream)
+{
+   if (!stream)
+      return EOF;
+
+   return filestream_putc(stream, character);
+}
+
+int64_t rfflush(RFILE * stream)
+{
+   if (!stream)
+      return EOF;
+
+   return filestream_flush(stream);
+}
+
+int rfprintf(RFILE * stream, const char * format, ...)
+{
+   int result;
+   va_list vl;
+
+   if (!stream)
+      return -1;
+
+   va_start(vl, format);
+   result = filestream_vprintf(stream, format, vl);
+   va_end(vl);
+   return result;
+}
+
+int rferror(RFILE* stream)
+{
+   return filestream_error(stream);
+}
+
+int rfeof(RFILE* stream)
+{
+   return filestream_eof(stream);
+}
+
+int rfscanf(RFILE * stream, const char * format, ...)
+{
+   int result;
+   va_list vl;
+
+   if (!stream)
+      return 0;
+
+   va_start(vl, format);
+   result = filestream_vscanf(stream, format, &vl);
+   va_end(vl);
+   return result;
+}
diff --git a/deps/libretro-common/streams/interface_stream.c b/deps/libretro-common/streams/interface_stream.c
new file mode 100644 (file)
index 0000000..5f65c49
--- /dev/null
@@ -0,0 +1,806 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (interface_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+
+#include <streams/interface_stream.h>
+#include <streams/file_stream.h>
+#include <streams/memory_stream.h>
+#ifdef HAVE_CHD
+#include <streams/chd_stream.h>
+#endif
+#if defined(HAVE_ZLIB)
+#include <streams/rzip_stream.h>
+#endif
+#include <encodings/crc32.h>
+
+struct intfstream_internal
+{
+   struct
+   {
+      RFILE *fp;
+   } file;
+
+   struct
+   {
+      memstream_t *fp;
+      struct
+      {
+         uint8_t *data;
+         uint64_t size;
+      } buf;
+      bool writable;
+   } memory;
+#ifdef HAVE_CHD
+   struct
+   {
+      chdstream_t *fp;
+      int32_t track;
+   } chd;
+#endif
+#if defined(HAVE_ZLIB)
+   struct
+   {
+      rzipstream_t *fp;
+   } rzip;
+#endif
+   enum intfstream_type type;
+};
+
+int64_t intfstream_get_size(intfstream_internal_t *intf)
+{
+   if (!intf)
+      return 0;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return filestream_get_size(intf->file.fp);
+      case INTFSTREAM_MEMORY:
+         return intf->memory.buf.size;
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+        return chdstream_get_size(intf->chd.fp);
+#else
+        break;
+#endif
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return rzipstream_get_size(intf->rzip.fp);
+#else
+         break;
+#endif
+   }
+
+   return 0;
+}
+
+bool intfstream_resize(intfstream_internal_t *intf, intfstream_info_t *info)
+{
+   if (!intf || !info)
+      return false;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         break;
+      case INTFSTREAM_MEMORY:
+         intf->memory.buf.data = info->memory.buf.data;
+         intf->memory.buf.size = info->memory.buf.size;
+
+         memstream_set_buffer(intf->memory.buf.data,
+               intf->memory.buf.size);
+         break;
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+#endif
+         break;
+      case INTFSTREAM_RZIP:
+         /* Unsupported */
+         return false;
+   }
+
+   return true;
+}
+
+bool intfstream_open(intfstream_internal_t *intf, const char *path,
+      unsigned mode, unsigned hints)
+{
+   if (!intf)
+      return false;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         intf->file.fp = filestream_open(path, mode, hints);
+         if (!intf->file.fp)
+            return false;
+         break;
+      case INTFSTREAM_MEMORY:
+         intf->memory.fp = memstream_open(intf->memory.writable);
+         if (!intf->memory.fp)
+            return false;
+         break;
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         intf->chd.fp = chdstream_open(path, intf->chd.track);
+         if (!intf->chd.fp)
+            return false;
+         break;
+#else
+         return false;
+#endif
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         intf->rzip.fp = rzipstream_open(path, mode);
+         if (!intf->rzip.fp)
+            return false;
+         break;
+#else
+         return false;
+#endif
+   }
+
+   return true;
+}
+
+int intfstream_flush(intfstream_internal_t *intf)
+{
+   if (!intf)
+      return -1;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return filestream_flush(intf->file.fp);
+      case INTFSTREAM_MEMORY:
+      case INTFSTREAM_CHD:
+      case INTFSTREAM_RZIP:
+         /* Should we stub this for these interfaces? */
+         break;
+   }
+
+   return 0;
+}
+
+int intfstream_close(intfstream_internal_t *intf)
+{
+   if (!intf)
+      return -1;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         if (intf->file.fp)
+            return filestream_close(intf->file.fp);
+         return 0;
+      case INTFSTREAM_MEMORY:
+         if (intf->memory.fp)
+            memstream_close(intf->memory.fp);
+         return 0;
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         if (intf->chd.fp)
+            chdstream_close(intf->chd.fp);
+#endif
+         return 0;
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         if (intf->rzip.fp)
+            return rzipstream_close(intf->rzip.fp);
+#endif
+         return 0;
+   }
+
+   return -1;
+}
+
+void *intfstream_init(intfstream_info_t *info)
+{
+   intfstream_internal_t *intf = NULL;
+   if (!info)
+      goto error;
+
+   intf = (intfstream_internal_t*)malloc(sizeof(*intf));
+
+   if (!intf)
+      goto error;
+
+   intf->type            = info->type;
+   intf->file.fp         = NULL;
+   intf->memory.buf.data = NULL;
+   intf->memory.buf.size = 0;
+   intf->memory.fp       = NULL;
+   intf->memory.writable = false;
+#ifdef HAVE_CHD
+   intf->chd.track       = 0;
+   intf->chd.fp          = NULL;
+#endif
+#ifdef HAVE_ZLIB
+   intf->rzip.fp         = NULL;
+#endif
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         break;
+      case INTFSTREAM_MEMORY:
+         intf->memory.writable = info->memory.writable;
+         if (!intfstream_resize(intf, info))
+            goto error;
+         break;
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         intf->chd.track = info->chd.track;
+         break;
+#else
+         goto error;
+#endif
+      case INTFSTREAM_RZIP:
+         break;
+   }
+
+   return intf;
+
+error:
+   if (intf)
+      free(intf);
+   return NULL;
+}
+
+int64_t intfstream_seek(
+      intfstream_internal_t *intf, int64_t offset, int whence)
+{
+   if (!intf)
+      return -1;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         {
+            int seek_position = 0;
+            switch (whence)
+            {
+               case SEEK_SET:
+                  seek_position = RETRO_VFS_SEEK_POSITION_START;
+                  break;
+               case SEEK_CUR:
+                  seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
+                  break;
+               case SEEK_END:
+                  seek_position = RETRO_VFS_SEEK_POSITION_END;
+                  break;
+            }
+            return (int64_t)filestream_seek(intf->file.fp, (int64_t)offset,
+                  seek_position);
+         }
+      case INTFSTREAM_MEMORY:
+         return (int64_t)memstream_seek(intf->memory.fp, offset, whence);
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         return (int64_t)chdstream_seek(intf->chd.fp, offset, whence);
+#else
+         break;
+#endif
+      case INTFSTREAM_RZIP:
+         /* Unsupported */
+         break;
+   }
+
+   return -1;
+}
+
+int64_t intfstream_read(intfstream_internal_t *intf, void *s, uint64_t len)
+{
+   if (!intf)
+      return 0;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return filestream_read(intf->file.fp, s, len);
+      case INTFSTREAM_MEMORY:
+         return memstream_read(intf->memory.fp, s, len);
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         return chdstream_read(intf->chd.fp, s, len);
+#else
+         break;
+#endif
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return rzipstream_read(intf->rzip.fp, s, len);
+#else
+         break;
+#endif
+   }
+
+   return -1;
+}
+
+int64_t intfstream_write(intfstream_internal_t *intf,
+      const void *s, uint64_t len)
+{
+   if (!intf)
+      return 0;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return filestream_write(intf->file.fp, s, len);
+      case INTFSTREAM_MEMORY:
+         return memstream_write(intf->memory.fp, s, len);
+      case INTFSTREAM_CHD:
+         return -1;
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return rzipstream_write(intf->rzip.fp, s, len);
+#else
+         return -1;
+#endif
+   }
+
+   return 0;
+}
+
+int intfstream_printf(intfstream_internal_t *intf,
+      const char* format, ...)
+{
+   va_list vl;
+   int result;
+
+   if (!intf)
+      return 0;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         va_start(vl, format);
+         result = filestream_vprintf(intf->file.fp, format, vl);
+         va_end(vl);
+         return result;
+      case INTFSTREAM_MEMORY:
+         return -1;
+      case INTFSTREAM_CHD:
+         return -1;
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         va_start(vl, format);
+         result = rzipstream_vprintf(intf->rzip.fp, format, vl);
+         va_end(vl);
+         return result;
+#else
+         return -1;
+#endif
+   }
+
+   return 0;
+}
+
+int64_t intfstream_get_ptr(intfstream_internal_t* intf)
+{
+   if (!intf)
+      return 0;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return -1;
+      case INTFSTREAM_MEMORY:
+         return memstream_get_ptr(intf->memory.fp);
+      case INTFSTREAM_CHD:
+         return -1;
+      case INTFSTREAM_RZIP:
+         return -1;
+   }
+
+   return 0;
+}
+
+char *intfstream_gets(intfstream_internal_t *intf,
+      char *buffer, uint64_t len)
+{
+   if (!intf)
+      return NULL;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return filestream_gets(intf->file.fp,
+               buffer, (size_t)len);
+      case INTFSTREAM_MEMORY:
+         return memstream_gets(intf->memory.fp,
+               buffer, (size_t)len);
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         return chdstream_gets(intf->chd.fp, buffer, len);
+#else
+         break;
+#endif
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return rzipstream_gets(intf->rzip.fp, buffer, (size_t)len);
+#else
+         break;
+#endif
+   }
+
+   return NULL;
+}
+
+int intfstream_getc(intfstream_internal_t *intf)
+{
+   if (!intf)
+      return -1;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return filestream_getc(intf->file.fp);
+      case INTFSTREAM_MEMORY:
+         return memstream_getc(intf->memory.fp);
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         return chdstream_getc(intf->chd.fp);
+#else
+         break;
+#endif
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return rzipstream_getc(intf->rzip.fp);
+#else
+         break;
+#endif
+   }
+
+   return -1;
+}
+
+int64_t intfstream_tell(intfstream_internal_t *intf)
+{
+   if (!intf)
+      return -1;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return (int64_t)filestream_tell(intf->file.fp);
+      case INTFSTREAM_MEMORY:
+         return (int64_t)memstream_pos(intf->memory.fp);
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         return (int64_t)chdstream_tell(intf->chd.fp);
+#else
+         break;
+#endif
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return (int64_t)rzipstream_tell(intf->rzip.fp);
+#else
+         break;
+#endif
+   }
+
+   return -1;
+}
+
+int intfstream_eof(intfstream_internal_t *intf)
+{
+   if (!intf)
+      return -1;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return filestream_eof(intf->file.fp);
+      case INTFSTREAM_MEMORY:
+         /* TODO: Add this functionality to
+          * memory_stream interface */
+         break;
+      case INTFSTREAM_CHD:
+         /* TODO: Add this functionality to
+          * chd_stream interface */
+         break;
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return rzipstream_eof(intf->rzip.fp);
+#else
+         break;
+#endif
+   }
+
+   return -1;
+}
+
+void intfstream_rewind(intfstream_internal_t *intf)
+{
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         filestream_rewind(intf->file.fp);
+         break;
+      case INTFSTREAM_MEMORY:
+         memstream_rewind(intf->memory.fp);
+         break;
+      case INTFSTREAM_CHD:
+#ifdef HAVE_CHD
+         chdstream_rewind(intf->chd.fp);
+#endif
+         break;
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         rzipstream_rewind(intf->rzip.fp);
+#endif
+         break;
+   }
+}
+
+void intfstream_putc(intfstream_internal_t *intf, int c)
+{
+   if (!intf)
+      return;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         filestream_putc(intf->file.fp, c);
+         break;
+      case INTFSTREAM_MEMORY:
+         memstream_putc(intf->memory.fp, c);
+         break;
+      case INTFSTREAM_CHD:
+         break;
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         rzipstream_putc(intf->rzip.fp, c);
+#else
+         break;
+#endif
+   }
+}
+
+uint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf)
+{
+   if (intf)
+   {
+#ifdef HAVE_CHD
+      if (intf->type == INTFSTREAM_CHD)
+         return chdstream_get_track_start(intf->chd.fp);
+#endif
+   }
+
+   return 0;
+}
+
+uint32_t intfstream_get_frame_size(intfstream_internal_t *intf)
+{
+   if (intf)
+   {
+#ifdef HAVE_CHD
+      if (intf->type == INTFSTREAM_CHD)
+         return chdstream_get_frame_size(intf->chd.fp);
+#endif
+   }
+
+   return 0;
+}
+
+uint32_t intfstream_get_first_sector(intfstream_internal_t* intf)
+{
+   if (intf)
+   {
+#ifdef HAVE_CHD
+      if (intf->type == INTFSTREAM_CHD)
+         return chdstream_get_first_track_sector(intf->chd.fp);
+#endif
+   }
+
+   return 0;
+}
+
+bool intfstream_is_compressed(intfstream_internal_t *intf)
+{
+   if (!intf)
+      return false;
+
+   switch (intf->type)
+   {
+      case INTFSTREAM_FILE:
+         return false;
+      case INTFSTREAM_MEMORY:
+         return false;
+      case INTFSTREAM_CHD:
+         return true;
+      case INTFSTREAM_RZIP:
+#if defined(HAVE_ZLIB)
+         return rzipstream_is_compressed(intf->rzip.fp);
+#else
+         break;
+#endif
+   }
+
+   return false;
+}
+
+bool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc)
+{
+   int64_t data_read    = 0;
+   uint32_t accumulator = 0;
+   uint8_t buffer[4096];
+
+   if (!intf || !crc)
+      return false;
+
+   /* Ensure we start at the beginning of the file */
+   intfstream_rewind(intf);
+
+   while ((data_read = intfstream_read(intf, buffer, sizeof(buffer))) > 0)
+      accumulator = encoding_crc32(accumulator, buffer, (size_t)data_read);
+
+   if (data_read < 0)
+      return false;
+
+   *crc = accumulator;
+
+   /* Reset file to the beginning */
+   intfstream_rewind(intf);
+
+   return true;
+}
+
+intfstream_t* intfstream_open_file(const char *path,
+      unsigned mode, unsigned hints)
+{
+   intfstream_info_t info;
+   intfstream_t *fd = NULL;
+
+   info.type        = INTFSTREAM_FILE;
+   fd               = (intfstream_t*)intfstream_init(&info);
+
+   if (!fd)
+      return NULL;
+
+   if (!intfstream_open(fd, path, mode, hints))
+      goto error;
+
+   return fd;
+
+error:
+   if (fd)
+   {
+      intfstream_close(fd);
+      free(fd);
+   }
+   return NULL;
+}
+
+intfstream_t *intfstream_open_memory(void *data,
+      unsigned mode, unsigned hints, uint64_t size)
+{
+   intfstream_info_t info;
+   intfstream_t *fd     = NULL;
+
+   info.type            = INTFSTREAM_MEMORY;
+   info.memory.buf.data = (uint8_t*)data;
+   info.memory.buf.size = size;
+   info.memory.writable = false;
+
+   fd                   = (intfstream_t*)intfstream_init(&info);
+   if (!fd)
+      return NULL;
+
+   if (!intfstream_open(fd, NULL, mode, hints))
+      goto error;
+
+   return fd;
+
+error:
+   if (fd)
+   {
+      intfstream_close(fd);
+      free(fd);
+   }
+   return NULL;
+}
+
+intfstream_t *intfstream_open_writable_memory(void *data,
+      unsigned mode, unsigned hints, uint64_t size)
+{
+   intfstream_info_t info;
+   intfstream_t *fd     = NULL;
+
+   info.type            = INTFSTREAM_MEMORY;
+   info.memory.buf.data = (uint8_t*)data;
+   info.memory.buf.size = size;
+   info.memory.writable = true;
+
+   fd                   = (intfstream_t*)intfstream_init(&info);
+   if (!fd)
+      return NULL;
+
+   if (!intfstream_open(fd, NULL, mode, hints))
+      goto error;
+
+   return fd;
+
+error:
+   if (fd)
+   {
+      intfstream_close(fd);
+      free(fd);
+   }
+   return NULL;
+}
+
+intfstream_t *intfstream_open_chd_track(const char *path,
+      unsigned mode, unsigned hints, int32_t track)
+{
+   intfstream_info_t info;
+   intfstream_t *fd = NULL;
+
+   info.type        = INTFSTREAM_CHD;
+   info.chd.track   = track;
+
+   fd               = (intfstream_t*)intfstream_init(&info);
+
+   if (!fd)
+      return NULL;
+
+   if (!intfstream_open(fd, path, mode, hints))
+      goto error;
+
+   return fd;
+
+error:
+   if (fd)
+   {
+      intfstream_close(fd);
+      free(fd);
+   }
+   return NULL;
+}
+
+intfstream_t* intfstream_open_rzip_file(const char *path,
+      unsigned mode)
+{
+   intfstream_info_t info;
+   intfstream_t *fd = NULL;
+
+   info.type        = INTFSTREAM_RZIP;
+   fd               = (intfstream_t*)intfstream_init(&info);
+
+   if (!fd)
+      return NULL;
+
+   if (!intfstream_open(fd, path, mode, RETRO_VFS_FILE_ACCESS_HINT_NONE))
+      goto error;
+
+   return fd;
+
+error:
+   if (fd)
+   {
+      intfstream_close(fd);
+      free(fd);
+   }
+   return NULL;
+}
diff --git a/deps/libretro-common/streams/memory_stream.c b/deps/libretro-common/streams/memory_stream.c
new file mode 100644 (file)
index 0000000..2aa1c80
--- /dev/null
@@ -0,0 +1,191 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (memory_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <streams/memory_stream.h>
+
+/* TODO/FIXME - static globals */
+static uint8_t* g_buffer      = NULL;
+static uint64_t g_size         = 0;
+static uint64_t last_file_size = 0;
+
+struct memstream
+{
+   uint64_t size;
+   uint64_t ptr;
+   uint64_t max_ptr;
+   uint8_t *buf;
+   unsigned writing;
+};
+
+void memstream_set_buffer(uint8_t *buffer, uint64_t size)
+{
+   g_buffer = buffer;
+   g_size   = size;
+}
+
+uint64_t memstream_get_last_size(void)
+{
+   return last_file_size;
+}
+
+memstream_t *memstream_open(unsigned writing)
+{
+   memstream_t *stream;
+   if (!g_buffer || !g_size)
+      return NULL;
+
+   stream = (memstream_t*)malloc(sizeof(*stream));
+
+   if (!stream)
+      return NULL;
+
+   stream->buf       = g_buffer;
+   stream->size      = g_size;
+   stream->ptr       = 0;
+   stream->max_ptr   = 0;
+   stream->writing   = writing;
+
+   g_buffer          = NULL;
+   g_size            = 0;
+
+   return stream;
+}
+
+void memstream_close(memstream_t *stream)
+{
+   if (!stream)
+      return;
+
+   last_file_size = stream->writing ? stream->max_ptr : stream->size;
+   free(stream);
+}
+
+uint64_t memstream_get_ptr(memstream_t *stream)
+{
+   return stream->ptr;
+}
+
+uint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes)
+{
+   uint64_t avail = 0;
+
+   if (!stream)
+      return 0;
+
+   avail               = stream->size - stream->ptr;
+   if (bytes > avail)
+      bytes            = avail;
+
+   memcpy(data, stream->buf + stream->ptr, (size_t)bytes);
+   stream->ptr        += bytes;
+   if (stream->ptr > stream->max_ptr)
+      stream->max_ptr  = stream->ptr;
+   return bytes;
+}
+
+uint64_t memstream_write(memstream_t *stream,
+      const void *data, uint64_t bytes)
+{
+   uint64_t avail = 0;
+
+   if (!stream)
+      return 0;
+
+   avail = stream->size - stream->ptr;
+   if (bytes > avail)
+      bytes = avail;
+
+   memcpy(stream->buf + stream->ptr, data, (size_t)bytes);
+   stream->ptr += bytes;
+   if (stream->ptr > stream->max_ptr)
+      stream->max_ptr = stream->ptr;
+   return bytes;
+}
+
+int64_t memstream_seek(memstream_t *stream, int64_t offset, int whence)
+{
+   uint64_t ptr;
+
+   switch (whence)
+   {
+      case SEEK_SET:
+         ptr = offset;
+         break;
+      case SEEK_CUR:
+         ptr = stream->ptr + offset;
+         break;
+      case SEEK_END:
+         ptr = (stream->writing ? stream->max_ptr : stream->size) + offset;
+         break;
+      default:
+         return -1;
+   }
+
+   if (ptr <= stream->size)
+   {
+      stream->ptr = ptr;
+      return 0;
+   }
+
+   return -1;
+}
+
+void memstream_rewind(memstream_t *stream)
+{
+   memstream_seek(stream, 0L, SEEK_SET);
+}
+
+uint64_t memstream_pos(memstream_t *stream)
+{
+   return stream->ptr;
+}
+
+char *memstream_gets(memstream_t *stream, char *buffer, size_t len)
+{
+   return NULL;
+}
+
+int memstream_getc(memstream_t *stream)
+{
+   int ret = 0;
+   if (stream->ptr >= stream->size)
+      return EOF;
+   ret = stream->buf[stream->ptr++];
+
+   if (stream->ptr > stream->max_ptr)
+      stream->max_ptr = stream->ptr;
+
+   return ret;
+}
+
+void memstream_putc(memstream_t *stream, int c)
+{
+   if (stream->ptr < stream->size)
+      stream->buf[stream->ptr++] = c;
+
+   if (stream->ptr > stream->max_ptr)
+      stream->max_ptr = stream->ptr;
+}
diff --git a/deps/libretro-common/streams/network_stream.c b/deps/libretro-common/streams/network_stream.c
new file mode 100644 (file)
index 0000000..068fd95
--- /dev/null
@@ -0,0 +1,329 @@
+/* Copyright  (C) 2022 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (network_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <retro_endianness.h>
+
+#include <streams/network_stream.h>
+
+bool netstream_open(netstream_t *stream, void *buf, size_t size, size_t used)
+{
+   if (buf)
+   {
+      /* Pre-allocated buffer must have a non-zero size. */
+      if (!size || used > size)
+         return false;
+   }
+   else
+   {
+      if (size)
+      {
+         buf = malloc(size);
+         if (!buf)
+            return false;
+      }
+
+      used = 0;
+   }
+
+   stream->buf  = buf;
+   stream->size = size;
+   stream->used = used;
+   stream->pos  = 0;
+
+   return true;
+}
+
+void netstream_close(netstream_t *stream, bool dealloc)
+{
+   if (dealloc)
+      free(stream->buf);
+   memset(stream, 0, sizeof(*stream));
+}
+
+void netstream_reset(netstream_t *stream)
+{
+   stream->pos  = 0;
+   stream->used = 0;
+}
+
+bool netstream_truncate(netstream_t *stream, size_t used)
+{
+   if (used > stream->size)
+      return false;
+
+   stream->used = used;
+
+   /* If the current stream position is past our new end of stream,
+      set the current position to the end of the stream. */
+   if (stream->pos > used)
+      stream->pos = used;
+
+   return true;
+}
+
+void netstream_data(netstream_t *stream, void **data, size_t *len)
+{
+   *data = stream->buf;
+   *len  = stream->used;
+}
+
+bool netstream_eof(netstream_t *stream)
+{
+   return stream->pos >= stream->used;
+}
+
+size_t netstream_tell(netstream_t *stream)
+{
+   return stream->pos;
+}
+
+bool netstream_seek(netstream_t *stream, long offset, int origin)
+{
+   long pos  = (long)stream->pos;
+   long used = (long)stream->used;
+
+   switch (origin)
+   {
+      case NETSTREAM_SEEK_SET:
+         pos  = offset;
+         break;
+      case NETSTREAM_SEEK_CUR:
+         pos += offset;
+         break;
+      case NETSTREAM_SEEK_END:
+         pos  = used + offset;
+         break;
+      default:
+         return false;
+   }
+
+   if (pos < 0 || pos > used)
+      return false;
+
+   stream->pos = (size_t)pos;
+
+   return true;
+}
+
+bool netstream_read(netstream_t *stream, void *data, size_t len)
+{
+   size_t remaining = stream->used - stream->pos;
+
+   if (!data || !remaining || len > remaining)
+      return false;
+
+   /* If len is 0, read all remaining bytes. */
+   if (!len)
+      len = remaining;
+
+   memcpy(data, (uint8_t*)stream->buf + stream->pos, len);
+
+   stream->pos += len;
+
+   return true;
+}
+
+/* This one doesn't require any swapping. */
+bool netstream_read_byte(netstream_t *stream, uint8_t *data)
+{
+   return netstream_read(stream, data, sizeof(*data));
+}
+
+#define NETSTREAM_READ_TYPE(name, type, swap) \
+bool netstream_read_##name(netstream_t *stream, type *data) \
+{ \
+   if (!netstream_read(stream, data, sizeof(*data))) \
+      return false; \
+   *data = swap(*data); \
+   return true; \
+}
+
+NETSTREAM_READ_TYPE(word,  uint16_t, retro_be_to_cpu16)
+NETSTREAM_READ_TYPE(dword, uint32_t, retro_be_to_cpu32)
+NETSTREAM_READ_TYPE(qword, uint64_t, retro_be_to_cpu64)
+
+#undef NETSTREAM_READ_TYPE
+
+#ifdef __STDC_IEC_559__
+#define NETSTREAM_READ_TYPE(name, type, type_alt, swap) \
+bool netstream_read_##name(netstream_t *stream, type *data) \
+{ \
+   type_alt *data_alt = (type_alt*)data; \
+   if (!netstream_read(stream, data, sizeof(*data))) \
+      return false; \
+   *data_alt = swap(*data_alt); \
+   return true; \
+}
+
+NETSTREAM_READ_TYPE(float,  float,  uint32_t, retro_be_to_cpu32)
+NETSTREAM_READ_TYPE(double, double, uint64_t, retro_be_to_cpu64)
+
+#undef NETSTREAM_READ_TYPE
+#endif
+
+int netstream_read_string(netstream_t *stream, char *s, size_t len)
+{
+   char c;
+   int ret = 0;
+
+   if (!s || !len)
+      return -1;
+
+   for (; --len; ret++)
+   {
+      if (!netstream_read(stream, &c, sizeof(c)))
+         return -1;
+
+      *s++ = c;
+
+      if (!c)
+         break;
+   }
+
+   if (!len)
+   {
+      *s = '\0';
+
+      for (;; ret++)
+      {
+         if (!netstream_read(stream, &c, sizeof(c)))
+            return -1;
+         if (!c)
+            break;
+      }
+   }
+
+   return ret;
+}
+
+bool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len)
+{
+   if (!len)
+      return false;
+
+   if (!netstream_read(stream, s, len))
+      return false;
+
+   /* Ensure the string is always null-terminated. */
+   s[len - 1] = '\0';
+
+   return true;
+}
+
+bool netstream_write(netstream_t *stream, const void *data, size_t len)
+{
+   size_t remaining = stream->size - stream->pos;
+
+   if (!data || !len)
+      return false;
+
+   if (len > remaining)
+   {
+      if (!stream->size)
+      {
+         stream->buf  = malloc(len);
+         if (!stream->buf)
+            return false;
+         stream->size = len;
+      }
+      else
+      {
+         size_t size = stream->size + (len - remaining);
+         void   *buf = realloc(stream->buf, size);
+
+         if (!buf)
+            return false;
+
+         stream->buf  = buf;
+         stream->size = size;
+      }
+   }
+
+   memcpy((uint8_t*)stream->buf + stream->pos, data, len);
+
+   stream->pos += len;
+
+   if (stream->pos > stream->used)
+      stream->used = stream->pos;
+
+   return true;
+}
+
+/* This one doesn't require any swapping. */
+bool netstream_write_byte(netstream_t *stream, uint8_t data)
+{
+   return netstream_write(stream, &data, sizeof(data));
+}
+
+#define NETSTREAM_WRITE_TYPE(name, type, swap) \
+bool netstream_write_##name(netstream_t *stream, type data) \
+{ \
+   data = swap(data); \
+   return netstream_write(stream, &data, sizeof(data)); \
+}
+
+NETSTREAM_WRITE_TYPE(word,  uint16_t, retro_cpu_to_be16)
+NETSTREAM_WRITE_TYPE(dword, uint32_t, retro_cpu_to_be32)
+NETSTREAM_WRITE_TYPE(qword, uint64_t, retro_cpu_to_be64)
+
+#undef NETSTREAM_WRITE_TYPE
+
+#ifdef __STDC_IEC_559__
+#define NETSTREAM_WRITE_TYPE(name, type, type_alt, swap) \
+bool netstream_write_##name(netstream_t *stream, type data) \
+{ \
+   type_alt *data_alt = (type_alt*)&data; \
+   *data_alt = swap(*data_alt); \
+   return netstream_write(stream, &data, sizeof(data)); \
+}
+
+NETSTREAM_WRITE_TYPE(float,  float,  uint32_t, retro_cpu_to_be32)
+NETSTREAM_WRITE_TYPE(double, double, uint64_t, retro_cpu_to_be64)
+
+#undef NETSTREAM_WRITE_TYPE
+#endif
+
+bool netstream_write_string(netstream_t *stream, const char *s)
+{
+   if (!s)
+      return false;
+
+   return netstream_write(stream, s, strlen(s) + 1);
+}
+
+bool netstream_write_fixed_string(netstream_t *stream, const char *s,
+      size_t len)
+{
+   char end = '\0';
+
+   if (!netstream_write(stream, s, len))
+      return false;
+
+   /* Ensure the string is always null-terminated. */
+   netstream_seek(stream, -1, NETSTREAM_SEEK_CUR);
+   netstream_write(stream, &end, sizeof(end));
+
+   return true;
+}
diff --git a/deps/libretro-common/streams/rzip_stream.c b/deps/libretro-common/streams/rzip_stream.c
new file mode 100644 (file)
index 0000000..6f56fa6
--- /dev/null
@@ -0,0 +1,1069 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rzip_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <string/stdstring.h>
+#include <file/file_path.h>
+
+#include <streams/file_stream.h>
+#include <streams/trans_stream.h>
+
+#include <streams/rzip_stream.h>
+
+/* Current RZIP file format version */
+#define RZIP_VERSION 1
+
+/* Compression level
+ * > zlib default of 6 provides the best
+ *   balance between file size and
+ *   compression speed */
+#define RZIP_COMPRESSION_LEVEL 6
+
+/* Default chunk size: 128kb */
+#define RZIP_DEFAULT_CHUNK_SIZE 131072
+
+/* Header sizes (in bytes) */
+#define RZIP_HEADER_SIZE 20
+#define RZIP_CHUNK_HEADER_SIZE 4
+
+/* Holds all metadata for an RZIP file stream */
+struct rzipstream
+{
+   uint64_t size;
+   /* virtual_ptr: Used to track how much
+    * uncompressed data has been read */
+   uint64_t virtual_ptr;
+   RFILE* file;
+   const struct trans_stream_backend *deflate_backend;
+   void *deflate_stream;
+   const struct trans_stream_backend *inflate_backend;
+   void *inflate_stream;
+   uint8_t *in_buf;
+   uint8_t *out_buf;
+   uint32_t in_buf_size;
+   uint32_t in_buf_ptr;
+   uint32_t out_buf_size;
+   uint32_t out_buf_ptr;
+   uint32_t out_buf_occupancy;
+   uint32_t chunk_size;
+   bool is_compressed;
+   bool is_writing;
+};
+
+/* Header Functions */
+
+/* Reads header information from RZIP file
+ * > Detects whether file is compressed or
+ *   uncompressed data
+ * > If compressed, extracts uncompressed
+ *   file/chunk sizes */
+static bool rzipstream_read_file_header(rzipstream_t *stream)
+{
+   unsigned i;
+   int64_t length;
+   uint8_t header_bytes[RZIP_HEADER_SIZE];
+
+   if (!stream)
+      return false;
+
+   for (i = 0; i < RZIP_HEADER_SIZE; i++)
+      header_bytes[i] = 0;
+
+   /* Attempt to read header bytes */
+   if ((length = filestream_read(stream->file, header_bytes, sizeof(header_bytes))) <= 0)
+      return false;
+
+   /* If file length is less than header size
+    * then assume this is uncompressed data */
+
+   /* Check 'magic numbers' - first 8 bytes
+    * of header */
+   if (
+       (length       < RZIP_HEADER_SIZE) || 
+       (header_bytes[0] !=           35) || /* # */
+       (header_bytes[1] !=           82) || /* R */
+       (header_bytes[2] !=           90) || /* Z */
+       (header_bytes[3] !=           73) || /* I */
+       (header_bytes[4] !=           80) || /* P */
+       (header_bytes[5] !=          118) || /* v */
+       (header_bytes[6] != RZIP_VERSION) || /* file format version number */
+       (header_bytes[7] !=           35))   /* # */
+   {
+      /* Reset file to start */
+      filestream_seek(stream->file, 0, SEEK_SET);
+      /* Get 'raw' file size */
+      stream->size          = filestream_get_size(stream->file);
+      stream->is_compressed = false;
+      return true;
+   }
+
+   /* Get uncompressed chunk size - next 4 bytes */
+   if ((stream->chunk_size = ((uint32_t)header_bytes[11] << 24) |
+                        ((uint32_t)header_bytes[10] << 16) |
+                        ((uint32_t)header_bytes[9]  <<  8) |
+                         (uint32_t)header_bytes[8]) == 0)
+      return false;
+
+   /* Get total uncompressed data size - next 8 bytes */
+   if ((stream->size = ((uint64_t)header_bytes[19] << 56) |
+                  ((uint64_t)header_bytes[18] << 48) |
+                  ((uint64_t)header_bytes[17] << 40) |
+                  ((uint64_t)header_bytes[16] << 32) |
+                  ((uint64_t)header_bytes[15] << 24) |
+                  ((uint64_t)header_bytes[14] << 16) |
+                  ((uint64_t)header_bytes[13] <<  8) |
+                   (uint64_t)header_bytes[12]) == 0)
+      return false;
+
+   stream->is_compressed = true;
+   return true;
+}
+
+/* Writes header information to RZIP file
+ * > ID 'magic numbers' + uncompressed
+ *   file/chunk sizes */
+static bool rzipstream_write_file_header(rzipstream_t *stream)
+{
+   unsigned i;
+   uint8_t header_bytes[RZIP_HEADER_SIZE];
+
+   if (!stream)
+      return false;
+
+   /* Populate header array */
+   for (i = 0; i < RZIP_HEADER_SIZE; i++)
+      header_bytes[i] = 0;
+
+   /* > 'Magic numbers' - first 8 bytes */
+   header_bytes[0]    =        35;    /* # */
+   header_bytes[1]    =        82;    /* R */
+   header_bytes[2]    =        90;    /* Z */
+   header_bytes[3]    =        73;    /* I */
+   header_bytes[4]    =        80;    /* P */
+   header_bytes[5]    =       118;    /* v */
+   header_bytes[6]    = RZIP_VERSION; /* file format version number */
+   header_bytes[7]    =        35;    /* # */
+
+   /* > Uncompressed chunk size - next 4 bytes */
+   header_bytes[11]   = (stream->chunk_size >> 24) & 0xFF;
+   header_bytes[10]   = (stream->chunk_size >> 16) & 0xFF;
+   header_bytes[9]    = (stream->chunk_size >>  8) & 0xFF;
+   header_bytes[8]    =  stream->chunk_size        & 0xFF;
+
+   /* > Total uncompressed data size - next 8 bytes */
+   header_bytes[19]   = (stream->size >> 56) & 0xFF;
+   header_bytes[18]   = (stream->size >> 48) & 0xFF;
+   header_bytes[17]   = (stream->size >> 40) & 0xFF;
+   header_bytes[16]   = (stream->size >> 32) & 0xFF;
+   header_bytes[15]   = (stream->size >> 24) & 0xFF;
+   header_bytes[14]   = (stream->size >> 16) & 0xFF;
+   header_bytes[13]   = (stream->size >>  8) & 0xFF;
+   header_bytes[12]   =  stream->size        & 0xFF;
+
+   /* Reset file to start */
+   filestream_seek(stream->file, 0, SEEK_SET);
+
+   /* Write header bytes */
+   return (filestream_write(stream->file,
+         header_bytes, sizeof(header_bytes)) == RZIP_HEADER_SIZE);
+}
+
+/* Stream Initialisation/De-initialisation */
+
+/* Initialises all members of an rzipstream_t struct,
+ * reading config from existing file header if available */
+static bool rzipstream_init_stream(
+      rzipstream_t *stream, const char *path, bool is_writing)
+{
+   unsigned file_mode;
+
+   if (!stream)
+      return false;
+
+   /* Ensure stream has valid initial values */
+   stream->size              = 0;
+   stream->chunk_size        = RZIP_DEFAULT_CHUNK_SIZE;
+   stream->file              = NULL;
+   stream->deflate_backend   = NULL;
+   stream->deflate_stream    = NULL;
+   stream->inflate_backend   = NULL;
+   stream->inflate_stream    = NULL;
+   stream->in_buf            = NULL;
+   stream->in_buf_size       = 0;
+   stream->in_buf_ptr        = 0;
+   stream->out_buf           = NULL;
+   stream->out_buf_size      = 0;
+   stream->out_buf_ptr       = 0;
+   stream->out_buf_occupancy = 0;
+
+   /* Check whether this is a read or write stream */
+   stream->is_writing = is_writing;
+   if (stream->is_writing)
+   {
+      /* Written files are always compressed */
+      stream->is_compressed = true;
+      file_mode             = RETRO_VFS_FILE_ACCESS_WRITE;
+   }
+   /* For read files, must get compression status
+    * from file itself... */
+   else
+      file_mode             = RETRO_VFS_FILE_ACCESS_READ;
+
+   /* Open file */
+   if (!(stream->file = filestream_open(
+         path, file_mode, RETRO_VFS_FILE_ACCESS_HINT_NONE)))
+      return false;
+
+   /* If file is open for writing, output header
+    * (Size component cannot be written until
+    * file is closed...) */
+   if (stream->is_writing)
+   {
+      /* Note: could just write zeros here, but
+       * still want to identify this as an RZIP
+       * file if writing fails partway through */
+      if (!rzipstream_write_file_header(stream))
+         return false;
+   }
+   /* If file is open for reading, parse any existing
+    * header */
+   else if (!rzipstream_read_file_header(stream))
+      return false;
+
+   /* Initialise appropriate transform stream
+    * and determine associated buffer sizes */
+   if (stream->is_writing)
+   {
+      /* Compression */
+      if (!(stream->deflate_backend = trans_stream_get_zlib_deflate_backend()))
+         return false;
+
+      if (!(stream->deflate_stream = stream->deflate_backend->stream_new()))
+         return false;
+
+      /* Set compression level */
+      if (!stream->deflate_backend->define(
+            stream->deflate_stream, "level", RZIP_COMPRESSION_LEVEL))
+         return false;
+
+      /* Buffers
+       * > Input: uncompressed
+       * > Output: compressed */
+      stream->in_buf_size  = stream->chunk_size;
+      stream->out_buf_size = stream->chunk_size * 2;
+      /* > Account for minimum zlib overhead
+       *   of 11 bytes... */ 
+      stream->out_buf_size =
+            (stream->out_buf_size < (stream->in_buf_size + 11)) ?
+                  stream->out_buf_size + 11 :
+                  stream->out_buf_size;
+
+      /* Redundant safety check */
+      if (   (stream->in_buf_size  == 0)
+          || (stream->out_buf_size == 0))
+         return false;
+   }
+   /* When reading, don't need an inflate transform
+    * stream (or buffers) if source file is uncompressed */
+   else if (stream->is_compressed)
+   {
+      /* Decompression */
+      if (!(stream->inflate_backend = trans_stream_get_zlib_inflate_backend()))
+         return false;
+
+      if (!(stream->inflate_stream = stream->inflate_backend->stream_new()))
+         return false;
+
+      /* Buffers
+       * > Input: compressed
+       * > Output: uncompressed
+       * Note 1: Actual compressed chunk sizes are read
+       *         from the file - just allocate a sensible
+       *         default to minimise memory reallocations
+       * Note 2: If file header is valid, output buffer
+       *         should have a size of exactly stream->chunk_size.
+       *         Allocate some additional space, just for
+       *         redundant safety... */
+      stream->in_buf_size  = stream->chunk_size * 2;
+      stream->out_buf_size = stream->chunk_size + (stream->chunk_size >> 2);
+
+      /* Redundant safety check */
+      if (   (stream->in_buf_size  == 0)
+          || (stream->out_buf_size == 0))
+         return false;
+   }
+
+   /* Allocate buffers */
+   if (stream->in_buf_size > 0)
+   {
+      if (!(stream->in_buf = (uint8_t *)calloc(stream->in_buf_size, 1)))
+         return false;
+   }
+
+   if (stream->out_buf_size > 0)
+   {
+      if (!(stream->out_buf = (uint8_t *)calloc(stream->out_buf_size, 1)))
+         return false;
+   }
+
+   return true;
+}
+
+/* free()'s all members of an rzipstream_t struct
+ * > Also closes associated file, if currently open */
+static int rzipstream_free_stream(rzipstream_t *stream)
+{
+   int ret = 0;
+
+   if (!stream)
+      return -1;
+
+   /* Free transform streams */
+   if (stream->deflate_stream && stream->deflate_backend)
+      stream->deflate_backend->stream_free(stream->deflate_stream);
+
+   stream->deflate_stream  = NULL;
+   stream->deflate_backend = NULL;
+
+   if (stream->inflate_stream && stream->inflate_backend)
+      stream->inflate_backend->stream_free(stream->inflate_stream);
+
+   stream->inflate_stream  = NULL;
+   stream->inflate_backend = NULL;
+
+   /* Free buffers */
+   if (stream->in_buf)
+      free(stream->in_buf);
+   stream->in_buf = NULL;
+
+   if (stream->out_buf)
+      free(stream->out_buf);
+   stream->out_buf = NULL;
+
+   /* Close file */
+   if (stream->file)
+      ret = filestream_close(stream->file);
+   stream->file = NULL;
+
+   free(stream);
+
+   return ret;
+}
+
+/* File Open */
+
+/* Opens a new or existing RZIP file
+ * > Supported 'mode' values are:
+ *   - RETRO_VFS_FILE_ACCESS_READ
+ *   - RETRO_VFS_FILE_ACCESS_WRITE
+ * > When reading, 'path' may reference compressed
+ *   or uncompressed data
+ * Returns NULL if arguments are invalid, file
+ * is invalid or an IO error occurs */
+rzipstream_t* rzipstream_open(const char *path, unsigned mode)
+{
+   rzipstream_t *stream = NULL;
+
+   /* Sanity check
+    * > Only RETRO_VFS_FILE_ACCESS_READ and
+    *   RETRO_VFS_FILE_ACCESS_WRITE are supported */
+   if (string_is_empty(path) ||
+       ((mode != RETRO_VFS_FILE_ACCESS_READ) &&
+        (mode != RETRO_VFS_FILE_ACCESS_WRITE)))
+      return NULL;
+
+   /* If opening in read mode, ensure file exists */
+   if ((mode == RETRO_VFS_FILE_ACCESS_READ) &&
+       !path_is_valid(path))
+      return NULL;
+
+   /* Allocate stream object */
+   if (!(stream = (rzipstream_t*)malloc(sizeof(*stream))))
+      return NULL;
+
+   stream->is_compressed   = false;
+   stream->is_writing      = false;
+   stream->size            = 0;
+   stream->chunk_size      = 0;
+   stream->virtual_ptr     = 0;
+   stream->file            = NULL;
+   stream->deflate_backend = NULL;
+   stream->deflate_stream  = NULL;
+   stream->inflate_backend = NULL;
+   stream->inflate_stream  = NULL;
+   stream->in_buf          = NULL;
+   stream->in_buf_size     = 0;
+   stream->in_buf_ptr      = 0;
+   stream->out_buf         = NULL;
+   stream->out_buf_size    = 0;
+   stream->out_buf_ptr     = 0;
+   stream->out_buf_occupancy = 0;
+
+   /* Initialise stream */
+   if (!rzipstream_init_stream(
+         stream, path,
+         (mode == RETRO_VFS_FILE_ACCESS_WRITE)))
+   {
+      rzipstream_free_stream(stream);
+      return NULL;
+   }
+
+   return stream;
+}
+
+/* File Read */
+
+/* Reads and decompresses the next chunk of data
+ * in the RZIP file */
+static bool rzipstream_read_chunk(rzipstream_t *stream)
+{
+   unsigned i;
+   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];
+   uint32_t compressed_chunk_size;
+   uint32_t inflate_read;
+   uint32_t inflate_written;
+
+   if (!stream || !stream->inflate_backend || !stream->inflate_stream)
+      return false;
+
+   for (i = 0; i < RZIP_CHUNK_HEADER_SIZE; i++)
+      chunk_header_bytes[i] = 0;
+
+   /* Attempt to read chunk header bytes */
+   if (filestream_read(
+         stream->file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=
+         RZIP_CHUNK_HEADER_SIZE)
+      return false;
+
+   /* Get size of next compressed chunk */
+   compressed_chunk_size = ((uint32_t)chunk_header_bytes[3] << 24) |
+                           ((uint32_t)chunk_header_bytes[2] << 16) |
+                           ((uint32_t)chunk_header_bytes[1] <<  8) |
+                            (uint32_t)chunk_header_bytes[0];
+   if (compressed_chunk_size == 0)
+      return false;
+
+   /* Resize input buffer, if required */
+   if (compressed_chunk_size > stream->in_buf_size)
+   {
+      free(stream->in_buf);
+      stream->in_buf      = NULL;
+
+      stream->in_buf_size = compressed_chunk_size;
+      stream->in_buf      = (uint8_t *)calloc(stream->in_buf_size, 1);
+      if (!stream->in_buf)
+         return false;
+
+      /* Note: Uncompressed data size is fixed, and read
+       * from the file header - we therefore don't attempt
+       * to resize the output buffer (if it's too small, then
+       * that's an error condition) */
+   }
+
+   /* Read compressed chunk from file */
+   if (filestream_read(
+         stream->file, stream->in_buf, compressed_chunk_size) !=
+         compressed_chunk_size)
+      return false;
+
+   /* Decompress chunk data */
+   stream->inflate_backend->set_in(
+         stream->inflate_stream,
+         stream->in_buf, compressed_chunk_size);
+
+   stream->inflate_backend->set_out(
+         stream->inflate_stream,
+         stream->out_buf, stream->out_buf_size);
+
+   /* Note: We have to set 'flush == true' here, otherwise we
+    * can't guarantee that the entire chunk will be written
+    * to the output buffer - this is inefficient, but not
+    * much we can do... */
+   if (!stream->inflate_backend->trans(
+         stream->inflate_stream, true,
+         &inflate_read, &inflate_written, NULL))
+      return false;
+
+   /* Error checking */
+   if (inflate_read != compressed_chunk_size)
+      return false;
+
+   if ((inflate_written == 0) ||
+       (inflate_written > stream->out_buf_size))
+      return false;
+
+   /* Record current output buffer occupancy
+    * and reset pointer */
+   stream->out_buf_occupancy = inflate_written;
+   stream->out_buf_ptr       = 0;
+
+   return true;
+}
+
+/* Reads (a maximum of) 'len' bytes from an RZIP file.
+ * Returns actual number of bytes read, or -1 in
+ * the event of an error */
+int64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len)
+{
+   int64_t data_len  = len;
+   uint8_t *data_ptr = (uint8_t *)data;
+   int64_t data_read = 0;
+
+   if (!stream || stream->is_writing || !data)
+      return -1;
+
+   /* If we are reading uncompressed data, simply
+    * 'pass on' the direct file access request */
+   if (!stream->is_compressed)
+      return filestream_read(stream->file, data, len);
+
+   /* Process input data */
+   while (data_len > 0)
+   {
+      int64_t read_size = 0;
+
+      /* Check whether we have reached the end
+       * of the file */
+      if (stream->virtual_ptr >= stream->size)
+         return data_read;
+
+      /* If everything in the output buffer has already
+       * been read, grab and extract the next chunk
+       * from disk */
+      if (stream->out_buf_ptr >= stream->out_buf_occupancy)
+         if (!rzipstream_read_chunk(stream))
+            return -1;
+
+      /* Get amount of data to 'read out' this loop
+       * > i.e. minimum of remaining output buffer
+       *   occupancy and remaining 'read data' size */
+      if ((read_size = stream->out_buf_occupancy - stream->out_buf_ptr) >
+            data_len)
+         read_size = data_len;
+
+      /* Copy as much cached data as possible into
+       * the read buffer */
+      memcpy(data_ptr, stream->out_buf + stream->out_buf_ptr, (size_t)read_size);
+
+      /* Increment pointers and remaining length */
+      stream->out_buf_ptr += read_size;
+      data_ptr            += read_size;
+      data_len            -= read_size;
+
+      stream->virtual_ptr += read_size;
+
+      data_read           += read_size;
+   }
+
+   return data_read;
+}
+
+/* Reads next character from an RZIP file.
+ * Returns character value, or EOF if no data
+ * remains.
+ * Note: Always returns EOF if file is open
+ * for writing. */
+int rzipstream_getc(rzipstream_t *stream)
+{
+   char c = 0;
+
+   if (!stream || stream->is_writing)
+      return EOF;
+
+   /* Attempt to read a single character */
+   if (rzipstream_read(stream, &c, 1) == 1)
+      return (int)(unsigned char)c;
+
+   return EOF;
+}
+
+/* Reads one line from an RZIP file and stores it
+ * in the character array pointed to by 's'.
+ * It stops reading when either (len-1) characters
+ * are read, the newline character is read, or the
+ * end-of-file is reached, whichever comes first.
+ * On success, returns 's'. In the event of an error,
+ * or if end-of-file is reached and no characters
+ * have been read, returns NULL. */
+char* rzipstream_gets(rzipstream_t *stream, char *s, size_t len)
+{
+   size_t str_len;
+   int c         = 0;
+   char *str_ptr = s;
+
+   if (!stream || stream->is_writing || (len == 0))
+      return NULL;
+
+   /* Read bytes until newline or EOF is reached,
+    * or string buffer is full */
+   for (str_len = (len - 1); str_len > 0; str_len--)
+   {
+      /* Get next character */
+      c = rzipstream_getc(stream);
+
+      /* Check for newline and EOF */
+      if (c == EOF)
+         break;
+
+      /* Copy character to string buffer */
+      *str_ptr++ = c;
+
+      /* Check for newline and EOF */
+      if (c == '\n')
+          break;
+   }
+
+   /* Add NUL termination */
+   *str_ptr = '\0';
+
+   /* Check whether EOF has been reached without
+    * reading any characters */
+   if ((str_ptr == s) && (c == EOF))
+      return NULL;
+
+   return (s);
+}
+
+/* Reads all data from file specified by 'path' and
+ * copies it to 'buf'.
+ * - 'buf' will be allocated and must be free()'d manually.
+ * - Allocated 'buf' size is equal to 'len'.
+ * Returns false in the event of an error */
+bool rzipstream_read_file(const char *path, void **buf, int64_t *len)
+{
+   int64_t bytes_read       = 0;
+   void *content_buf        = NULL;
+   int64_t content_buf_size = 0;
+   rzipstream_t *stream     = NULL;
+
+   if (!buf)
+      return false;
+
+   /* Attempt to open file */
+   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_READ)))
+   {
+      *buf = NULL;
+      return false;
+   }
+
+   /* Get file size */
+   if ((content_buf_size = rzipstream_get_size(stream)) < 0)
+      goto error;
+
+   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
+      goto error;
+
+   /* Allocate buffer */
+   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))
+      goto error;
+
+   /* Read file contents */
+   if ((bytes_read = rzipstream_read(stream, content_buf, content_buf_size)) <
+         0)
+      goto error;
+
+   /* Close file */
+   rzipstream_close(stream);
+   stream = NULL;
+
+   /* Add NUL termination for easy/safe handling of strings.
+    * Will only work with sane character formatting (Unix). */
+   ((char*)content_buf)[bytes_read] = '\0';
+
+   /* Assign buffer */
+   *buf = content_buf;
+
+   /* Assign length value, if required */
+   if (len)
+      *len = bytes_read;
+
+   return true;
+
+error:
+   if (stream)
+      rzipstream_close(stream);
+   stream = NULL;
+
+   if (content_buf)
+      free(content_buf);
+   content_buf = NULL;
+
+   if (len)
+      *len = -1;
+
+   *buf = NULL;
+
+   return false;
+}
+
+/* File Write */
+
+/* Compresses currently cached data and writes it
+ * as the next RZIP file chunk */
+static bool rzipstream_write_chunk(rzipstream_t *stream)
+{
+   unsigned i;
+   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];
+   uint32_t deflate_read;
+   uint32_t deflate_written;
+
+   if (!stream || !stream->deflate_backend || !stream->deflate_stream)
+      return false;
+
+   for (i = 0; i < RZIP_CHUNK_HEADER_SIZE; i++)
+      chunk_header_bytes[i] = 0;
+
+   /* Compress data currently held in input buffer */
+   stream->deflate_backend->set_in(
+         stream->deflate_stream,
+         stream->in_buf, stream->in_buf_ptr);
+
+   stream->deflate_backend->set_out(
+         stream->deflate_stream,
+         stream->out_buf, stream->out_buf_size);
+
+   /* Note: We have to set 'flush == true' here, otherwise we
+    * can't guarantee that the entire chunk will be written
+    * to the output buffer - this is inefficient, but not
+    * much we can do... */
+   if (!stream->deflate_backend->trans(
+         stream->deflate_stream, true,
+         &deflate_read, &deflate_written, NULL))
+      return false;
+
+   /* Error checking */
+   if (deflate_read != stream->in_buf_ptr)
+      return false;
+
+   if ((deflate_written == 0) ||
+       (deflate_written > stream->out_buf_size))
+      return false;
+
+   /* Write compressed chunk size to file */
+   chunk_header_bytes[3] = (deflate_written >> 24) & 0xFF;
+   chunk_header_bytes[2] = (deflate_written >> 16) & 0xFF;
+   chunk_header_bytes[1] = (deflate_written >>  8) & 0xFF;
+   chunk_header_bytes[0] =  deflate_written        & 0xFF;
+
+   if (filestream_write(
+         stream->file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=
+         RZIP_CHUNK_HEADER_SIZE)
+      return false;
+
+   /* Write compressed data to file */
+   if (filestream_write(
+         stream->file, stream->out_buf, deflate_written) != deflate_written)
+      return false;
+
+   /* Reset input buffer pointer */
+   stream->in_buf_ptr = 0;
+
+   return true;
+}
+
+/* Writes 'len' bytes to an RZIP file.
+ * Returns actual number of bytes written, or -1
+ * in the event of an error */
+int64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len)
+{
+   int64_t data_len        = len;
+   const uint8_t *data_ptr = (const uint8_t *)data;
+
+   if (!stream || !stream->is_writing || !data)
+      return -1;
+
+   /* Process input data */
+   while (data_len > 0)
+   {
+      int64_t cache_size = 0;
+
+      /* If input buffer is full, compress and write to disk */
+      if (stream->in_buf_ptr >= stream->in_buf_size)
+         if (!rzipstream_write_chunk(stream))
+            return -1;
+
+      /* Get amount of data to cache during this loop
+       * > i.e. minimum of space remaining in input buffer
+       *   and remaining 'write data' size */
+      if ((cache_size = stream->in_buf_size - stream->in_buf_ptr) > data_len)
+         cache_size = data_len;
+
+      /* Copy as much data as possible into
+       * the input buffer */
+      memcpy(stream->in_buf + stream->in_buf_ptr, data_ptr, (size_t)cache_size);
+
+      /* Increment pointers and remaining length */
+      stream->in_buf_ptr  += cache_size;
+      data_ptr            += cache_size;
+      data_len            -= cache_size;
+
+      stream->size        += cache_size;
+      stream->virtual_ptr += cache_size;
+   }
+
+   /* We always write the specified number of bytes
+    * (unless rzipstream_write_chunk() fails, in
+    * which we register a complete failure...) */
+   return len;
+}
+
+/* Writes a single character to an RZIP file.
+ * Returns character written, or EOF in the event
+ * of an error */
+int rzipstream_putc(rzipstream_t *stream, int c)
+{
+   char c_char = (char)c;
+
+   if (!stream || !stream->is_writing)
+      return EOF;
+
+   return (rzipstream_write(stream, &c_char, 1) == 1) ?
+         (int)(unsigned char)c : EOF;
+}
+
+/* Writes a variable argument list to an RZIP file.
+ * Ugly 'internal' function, required to enable
+ * 'printf' support in the higher level 'interface_stream'.
+ * Returns actual number of bytes written, or -1
+ * in the event of an error */
+int rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args)
+{
+   static char buffer[8 * 1024] = {0};
+   int64_t num_chars            = vsnprintf(buffer,
+         sizeof(buffer), format, args);
+
+   if (num_chars < 0)
+      return -1;
+   else if (num_chars == 0)
+      return 0;
+
+   return (int)rzipstream_write(stream, buffer, num_chars);
+}
+
+/* Writes formatted output to an RZIP file.
+ * Returns actual number of bytes written, or -1
+ * in the event of an error */
+int rzipstream_printf(rzipstream_t *stream, const char* format, ...)
+{
+   va_list vl;
+   int result = 0;
+
+   /* Initialise variable argument list */
+   va_start(vl, format);
+
+   /* Write variable argument list to file */
+   result = rzipstream_vprintf(stream, format, vl);
+
+   /* End using variable argument list */
+   va_end(vl);
+
+   return result;
+}
+
+/* Writes contents of 'data' buffer to file
+ * specified by 'path'.
+ * Returns false in the event of an error */
+bool rzipstream_write_file(const char *path, const void *data, int64_t len)
+{
+   int64_t bytes_written = 0;
+   rzipstream_t *stream  = NULL;
+
+   if (!data)
+      return false;
+
+   /* Attempt to open file */
+   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_WRITE)))
+      return false;
+
+   /* Write contents of data buffer to file */
+   bytes_written = rzipstream_write(stream, data, len);
+
+   /* Close file */
+   if (rzipstream_close(stream) == -1)
+      return false;
+
+   /* Check that the correct number of bytes
+    * were written */
+   return (bytes_written == len);
+}
+
+/* File Control */
+
+/* Sets file position to the beginning of the
+ * specified RZIP file.
+ * Note: It is not recommended to rewind a file
+ * that is open for writing, since the caller
+ * may end up with a file containing junk data
+ * at the end (harmless, but a waste of space). */
+void rzipstream_rewind(rzipstream_t *stream)
+{
+   if (!stream)
+      return;
+
+   /* Note: rzipstream_rewind() has no way of
+    * reporting errors (higher level interface
+    * requires a void return type) - so if anything
+    * goes wrong, all we can do is print to stderr
+    * and bail out... */
+
+   /* If we are handling uncompressed data, simply
+    * 'pass on' the direct file access request */
+   if (!stream->is_compressed)
+   {
+      filestream_rewind(stream->file);
+      return;
+   }
+
+   /* If no file access has yet occurred, file is
+    * already at the beginning -> do nothing */
+   if (stream->virtual_ptr == 0)
+      return;
+
+   /* Check whether we are reading or writing */
+   if (stream->is_writing)
+   {
+      /* Reset file position to first chunk location */
+      filestream_seek(stream->file, RZIP_HEADER_SIZE, SEEK_SET);
+      if (filestream_error(stream->file))
+         return;
+
+      /* Reset pointers */
+      stream->virtual_ptr = 0;
+      stream->in_buf_ptr  = 0;
+
+      /* Reset file size */
+      stream->size        = 0;
+   }
+   else
+   {
+      /* Check whether first file chunk is currently
+       * buffered in memory */
+      if ((stream->virtual_ptr < stream->chunk_size) &&
+          (stream->out_buf_ptr < stream->out_buf_occupancy))
+      {
+         /* It is: No file access is therefore required
+          * > Just reset pointers */
+         stream->virtual_ptr = 0;
+         stream->out_buf_ptr = 0;
+      }
+      else
+      {
+         /* It isn't: Have to re-read the first chunk
+          * from disk... */
+
+         /* Reset file position to first chunk location */
+         filestream_seek(stream->file, RZIP_HEADER_SIZE, SEEK_SET);
+         if (filestream_error(stream->file))
+            return;
+
+         /* Read chunk */
+         if (!rzipstream_read_chunk(stream))
+            return;
+
+         /* Reset pointers */
+         stream->virtual_ptr = 0;
+         stream->out_buf_ptr = 0;
+      }
+   }
+}
+
+/* File Status */
+
+/* Returns total size (in bytes) of the *uncompressed*
+ * data in an RZIP file.
+ * (If reading an uncompressed file, this corresponds
+ * to the 'physical' file size in bytes)
+ * Returns -1 in the event of a error. */
+int64_t rzipstream_get_size(rzipstream_t *stream)
+{
+   if (!stream)
+      return -1;
+
+   if (stream->is_compressed)
+      return stream->size;
+   return filestream_get_size(stream->file);
+}
+
+/* Returns EOF when no further *uncompressed* data
+ * can be read from an RZIP file. */
+int rzipstream_eof(rzipstream_t *stream)
+{
+   if (!stream)
+      return -1;
+
+   if (stream->is_compressed)
+      return (stream->virtual_ptr >= stream->size) ?
+            EOF : 0;
+   return filestream_eof(stream->file);
+}
+
+/* Returns the offset of the current byte of *uncompressed*
+ * data relative to the beginning of an RZIP file.
+ * Returns -1 in the event of a error. */
+int64_t rzipstream_tell(rzipstream_t *stream)
+{
+   if (!stream)
+      return -1;
+
+   if (stream->is_compressed)
+      return (int64_t)stream->virtual_ptr;
+   return filestream_tell(stream->file);
+}
+
+/* Returns true if specified RZIP file contains
+ * compressed content */
+bool rzipstream_is_compressed(rzipstream_t *stream)
+{
+   return stream && stream->is_compressed;
+}
+
+/* File Close */
+
+/* Closes RZIP file. If file is open for writing,
+ * flushes any remaining buffered data to disk.
+ * Returns -1 in the event of a error. */
+int rzipstream_close(rzipstream_t *stream)
+{
+   if (!stream)
+      return -1;
+
+   /* If we are writing, ensure that any
+    * remaining uncompressed data is flushed to
+    * disk and update file header */
+   if (stream->is_writing)
+   {
+      if (stream->in_buf_ptr > 0)
+         if (!rzipstream_write_chunk(stream))
+            goto error;
+
+      if (!rzipstream_write_file_header(stream))
+         goto error;
+   }
+
+   /* Free stream
+    * > This also closes the file */
+   return rzipstream_free_stream(stream);
+
+error:
+   /* Stream must be free()'d regardless */
+   rzipstream_free_stream(stream);
+   return -1;
+}
diff --git a/deps/libretro-common/streams/stdin_stream.c b/deps/libretro-common/streams/stdin_stream.c
new file mode 100644 (file)
index 0000000..80f6e9a
--- /dev/null
@@ -0,0 +1,151 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (stdin_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef _WIN32
+#ifndef _XBOX
+#include <windows.h>
+#endif
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <boolean.h>
+#include <retro_environment.h>
+#include <streams/stdin_stream.h>
+
+#if (defined(_WIN32) && defined(_XBOX)) || defined(__WINRT__) || !defined(__PSL1GHT__) && defined(__PS3__)
+size_t read_stdin(char *buf, size_t size)
+{
+   /* Not implemented. */
+   return 0;
+}
+#elif defined(_WIN32)
+size_t read_stdin(char *buf, size_t size)
+{
+   DWORD i;
+   DWORD has_read = 0;
+   DWORD avail    = 0;
+   bool echo      = false;
+   HANDLE hnd     = GetStdHandle(STD_INPUT_HANDLE);
+
+   if (hnd == INVALID_HANDLE_VALUE)
+      return 0;
+
+   /* Check first if we're a pipe
+    * (not console). */
+
+   /* If not a pipe, check if we're running in a console. */
+   if (!PeekNamedPipe(hnd, NULL, 0, NULL, &avail, NULL))
+   {
+      INPUT_RECORD recs[256];
+      bool has_key   = false;
+      DWORD mode     = 0;
+      DWORD has_read = 0;
+
+      if (!GetConsoleMode(hnd, &mode))
+         return 0;
+
+      if ((mode & (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))
+            && !SetConsoleMode(hnd,
+               mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)))
+         return 0;
+
+      /* Win32, Y U NO SANE NONBLOCK READ!? */
+      if (!PeekConsoleInput(hnd, recs,
+               sizeof(recs) / sizeof(recs[0]), &has_read))
+         return 0;
+
+      for (i = 0; i < has_read; i++)
+      {
+         /* Very crude, but should get the job done. */
+         if (recs[i].EventType == KEY_EVENT &&
+               recs[i].Event.KeyEvent.bKeyDown &&
+               (isgraph(recs[i].Event.KeyEvent.wVirtualKeyCode) ||
+                recs[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN))
+         {
+            has_key = true;
+            echo    = true;
+            avail   = size;
+            break;
+         }
+      }
+
+      if (!has_key)
+      {
+         FlushConsoleInputBuffer(hnd);
+         return 0;
+      }
+   }
+
+   if (!avail)
+      return 0;
+
+   if (avail > size)
+      avail = size;
+
+   if (!ReadFile(hnd, buf, avail, &has_read, NULL))
+      return 0;
+
+   for (i = 0; i < has_read; i++)
+      if (buf[i] == '\r')
+         buf[i] = '\n';
+
+   /* Console won't echo for us while in non-line mode,
+    * so do it manually ... */
+   if (echo)
+   {
+      HANDLE hnd_out = GetStdHandle(STD_OUTPUT_HANDLE);
+      if (hnd_out != INVALID_HANDLE_VALUE)
+      {
+         DWORD has_written;
+         WriteConsole(hnd_out, buf, has_read, &has_written, NULL);
+      }
+   }
+
+   return has_read;
+}
+#else
+size_t read_stdin(char *buf, size_t size)
+{
+   size_t has_read = 0;
+
+   while (size)
+   {
+      ssize_t ret = read(STDIN_FILENO, buf, size);
+
+      if (ret <= 0)
+         break;
+
+      buf      += ret;
+      has_read += ret;
+      size     -= ret;
+   }
+
+   return has_read;
+}
+#endif
diff --git a/deps/libretro-common/streams/trans_stream.c b/deps/libretro-common/streams/trans_stream.c
new file mode 100644 (file)
index 0000000..aecb457
--- /dev/null
@@ -0,0 +1,92 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (trans_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <streams/trans_stream.h>
+
+/**
+ * trans_stream_trans_full:
+ * @data                        : (optional) existing stream data, or a target
+ *                                for the new stream data to be saved
+ * @in                          : input data
+ * @in_size                     : input size
+ * @out                         : output data
+ * @out_size                    : output size
+ * @error                       : (optional) output for error code
+ *
+ * Perform a full transcoding from a source to a destination.
+ */
+bool trans_stream_trans_full(
+    struct trans_stream_backend *backend, void **data,
+    const uint8_t *in, uint32_t in_size,
+    uint8_t *out, uint32_t out_size,
+    enum trans_stream_error *error)
+{
+   void *rdata;
+   bool ret;
+   uint32_t rd, wn;
+
+   if (data && *data)
+      rdata = *data;
+   else
+   {
+      if (!(rdata = backend->stream_new()))
+      {
+         if (error)
+            *error = TRANS_STREAM_ERROR_ALLOCATION_FAILURE;
+         return false;
+      }
+   }
+
+   backend->set_in(rdata, in, in_size);
+   backend->set_out(rdata, out, out_size);
+   ret = backend->trans(rdata, true, &rd, &wn, error);
+
+   if (data)
+      *data = rdata;
+   else
+      backend->stream_free(rdata);
+
+   return ret;
+}
+
+const struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void)
+{
+#if HAVE_ZLIB
+   return &zlib_deflate_backend;
+#else
+   return NULL;
+#endif
+}
+
+const struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void)
+{
+#if HAVE_ZLIB
+   return &zlib_inflate_backend;
+#else
+   return NULL;
+#endif
+}
+
+const struct trans_stream_backend* trans_stream_get_pipe_backend(void)
+{
+   return &pipe_backend;
+}
diff --git a/deps/libretro-common/streams/trans_stream_pipe.c b/deps/libretro-common/streams/trans_stream_pipe.c
new file mode 100644 (file)
index 0000000..76f8b16
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (trans_stream_pipe.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <streams/trans_stream.h>
+
+struct pipe_trans_stream
+{
+   const uint8_t *in;
+   uint8_t *out;
+   uint32_t in_size, out_size;
+};
+
+static void *pipe_stream_new(void)
+{
+   struct pipe_trans_stream *stream = 
+      (struct pipe_trans_stream*)malloc(sizeof(*stream));
+   if (!stream)
+      return NULL;
+
+   stream->in                       = NULL;
+   stream->out                      = NULL;
+   stream->in_size                  = 0;
+   stream->out_size                 = 0;
+
+   return stream;
+}
+
+static void pipe_stream_free(void *data)
+{
+   free(data);
+}
+
+static void pipe_set_in(void *data, const uint8_t *in, uint32_t in_size)
+{
+   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;
+
+   if (!p)
+      return;
+         
+   p->in                       = in;
+   p->in_size                  = in_size;
+}
+
+static void pipe_set_out(void *data, uint8_t *out, uint32_t out_size)
+{
+   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;
+   
+   if (!p)
+      return;
+
+   p->out                      = out;
+   p->out_size                 = out_size;
+}
+
+static bool pipe_trans(
+   void *data, bool flush,
+   uint32_t *rd, uint32_t *wn,
+   enum trans_stream_error *error)
+{
+   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;
+
+   if (p->out_size < p->in_size)
+   {
+      memcpy(p->out, p->in, p->out_size);
+      *rd     = *wn = p->out_size;
+      p->in  += p->out_size;
+      p->out += p->out_size;
+      *error  = TRANS_STREAM_ERROR_BUFFER_FULL;
+      return false;
+   }
+
+   memcpy(p->out, p->in, p->in_size);
+   *rd     = *wn = p->in_size;
+   p->in  += p->in_size;
+   p->out += p->in_size;
+   *error  = TRANS_STREAM_ERROR_NONE;
+   return true;
+}
+
+const struct trans_stream_backend pipe_backend = {
+   "pipe",
+   &pipe_backend,
+   pipe_stream_new,
+   pipe_stream_free,
+   NULL,
+   pipe_set_in,
+   pipe_set_out,
+   pipe_trans
+};
diff --git a/deps/libretro-common/streams/trans_stream_zlib.c b/deps/libretro-common/streams/trans_stream_zlib.c
new file mode 100644 (file)
index 0000000..e5d1a4a
--- /dev/null
@@ -0,0 +1,330 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (trans_stream_zlib.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <zlib.h>
+#include <string/stdstring.h>
+#include <streams/trans_stream.h>
+
+struct zlib_trans_stream
+{
+   z_stream z;
+   int ex; /* window_bits or level */
+   bool inited;
+};
+
+static void *zlib_deflate_stream_new(void)
+{
+   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
+      malloc(sizeof(*ret));
+   if (!ret)
+      return NULL;
+   ret->inited      = false;
+   ret->ex          = 9;
+
+   ret->z.next_in   = NULL;
+   ret->z.avail_in  = 0;
+   ret->z.total_in  = 0;
+   ret->z.next_out  = NULL;
+   ret->z.avail_out = 0;
+   ret->z.total_out = 0;
+
+   ret->z.msg       = NULL;
+   ret->z.state     = NULL;
+
+   ret->z.zalloc    = NULL;
+   ret->z.zfree     = NULL;
+   ret->z.opaque    = NULL;
+
+   ret->z.data_type = 0;
+   ret->z.adler     = 0;
+   ret->z.reserved  = 0;
+   return (void *)ret;
+}
+
+static void *zlib_inflate_stream_new(void)
+{
+   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)
+      malloc(sizeof(*ret));
+   if (!ret)
+      return NULL;
+   ret->inited      = false;
+   ret->ex          = MAX_WBITS;
+
+   ret->z.next_in   = NULL;
+   ret->z.avail_in  = 0;
+   ret->z.total_in  = 0;
+   ret->z.next_out  = NULL;
+   ret->z.avail_out = 0;
+   ret->z.total_out = 0;
+
+   ret->z.msg       = NULL;
+   ret->z.state     = NULL;
+
+   ret->z.zalloc    = NULL;
+   ret->z.zfree     = NULL;
+   ret->z.opaque    = NULL;
+
+   ret->z.data_type = 0;
+   ret->z.adler     = 0;
+   ret->z.reserved  = 0;
+   return (void *)ret;
+}
+
+static void zlib_deflate_stream_free(void *data)
+{
+   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
+   if (!z)
+      return;
+   if (z->inited)
+      deflateEnd(&z->z);
+   free(z);
+}
+
+static void zlib_inflate_stream_free(void *data)
+{
+   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
+   if (!z)
+      return;
+   if (z->inited)
+      inflateEnd(&z->z);
+   if (z)
+      free(z);
+}
+
+static bool zlib_deflate_define(void *data, const char *prop, uint32_t val)
+{
+   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
+   if (string_is_equal(prop, "level"))
+   {
+      if (z)
+         z->ex = (int) val;
+      return true;
+   }
+   return false;
+}
+
+static bool zlib_inflate_define(void *data, const char *prop, uint32_t val)
+{
+   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
+   if (string_is_equal(prop, "window_bits"))
+   {
+      if (z)
+         z->ex = (int) val;
+      return true;
+   }
+   return false;
+}
+
+static void zlib_deflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
+{
+   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
+
+   if (!z)
+      return;
+
+   z->z.next_in                = (uint8_t *) in;
+   z->z.avail_in               = in_size;
+
+   if (!z->inited)
+   {
+      deflateInit(&z->z, z->ex);
+      z->inited = true;
+   }
+}
+
+static void zlib_inflate_set_in(void *data, const uint8_t *in, uint32_t in_size)
+{
+   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
+
+   if (!z)
+      return;
+
+   z->z.next_in                = (uint8_t *) in;
+   z->z.avail_in               = in_size;
+   if (!z->inited)
+   {
+      inflateInit2(&z->z, z->ex);
+      z->inited = true;
+   }
+}
+
+static void zlib_set_out(void *data, uint8_t *out, uint32_t out_size)
+{
+   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;
+
+   if (!z)
+      return;
+
+   z->z.next_out               = out;
+   z->z.avail_out              = out_size;
+}
+
+static bool zlib_deflate_trans(
+   void *data, bool flush,
+   uint32_t *rd, uint32_t *wn,
+   enum trans_stream_error *error)
+{
+   int zret                     = 0;
+   bool ret                     = false;
+   uint32_t pre_avail_in        = 0;
+   uint32_t pre_avail_out       = 0;
+   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
+   z_stream                  *z = &zt->z;
+
+   if (!zt->inited)
+   {
+      deflateInit(z, zt->ex);
+      zt->inited = true;
+   }
+
+   pre_avail_in  = z->avail_in;
+   pre_avail_out = z->avail_out;
+   zret          = deflate(z, flush ? Z_FINISH : Z_NO_FLUSH);
+
+   if (zret == Z_OK)
+   {
+      if (error)
+         *error = TRANS_STREAM_ERROR_AGAIN;
+   }
+   else if (zret == Z_STREAM_END)
+   {
+      if (error)
+         *error = TRANS_STREAM_ERROR_NONE;
+   }
+   else
+   {
+      if (error)
+         *error = TRANS_STREAM_ERROR_OTHER;
+      return false;
+   }
+   ret = true;
+
+   if (z->avail_out == 0)
+   {
+      /* Filled buffer, maybe an error */
+      if (z->avail_in != 0)
+      {
+         ret = false;
+         if (error)
+            *error = TRANS_STREAM_ERROR_BUFFER_FULL;
+      }
+   }
+
+   *rd = pre_avail_in - z->avail_in;
+   *wn = pre_avail_out - z->avail_out;
+
+   if (flush && zret == Z_STREAM_END)
+   {
+      deflateEnd(z);
+      zt->inited = false;
+   }
+
+   return ret;
+}
+
+static bool zlib_inflate_trans(
+   void *data, bool flush,
+   uint32_t *rd, uint32_t *wn,
+   enum trans_stream_error *error)
+{
+   int zret;
+   bool ret                     = false;
+   uint32_t pre_avail_in        = 0;
+   uint32_t pre_avail_out       = 0;
+   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;
+   z_stream                  *z = &zt->z;
+
+   if (!zt->inited)
+   {
+      inflateInit2(z, zt->ex);
+      zt->inited = true;
+   }
+
+   pre_avail_in  = z->avail_in;
+   pre_avail_out = z->avail_out;
+   zret          = inflate(z, flush ? Z_FINISH : Z_NO_FLUSH);
+
+   if (zret == Z_OK)
+   {
+      if (error)
+         *error = TRANS_STREAM_ERROR_AGAIN;
+   }
+   else if (zret == Z_STREAM_END)
+   {
+      if (error)
+         *error = TRANS_STREAM_ERROR_NONE;
+   }
+   else
+   {
+      if (error)
+         *error = TRANS_STREAM_ERROR_OTHER;
+      return false;
+   }
+   ret = true;
+
+   if (z->avail_out == 0)
+   {
+      /* Filled buffer, maybe an error */
+      if (z->avail_in != 0)
+      {
+         ret = false;
+         if (error)
+            *error = TRANS_STREAM_ERROR_BUFFER_FULL;
+      }
+   }
+
+   *rd = pre_avail_in - z->avail_in;
+   *wn = pre_avail_out - z->avail_out;
+
+   if (flush && zret == Z_STREAM_END)
+   {
+      inflateEnd(z);
+      zt->inited = false;
+   }
+
+   return ret;
+}
+
+const struct trans_stream_backend zlib_deflate_backend = {
+   "zlib_deflate",
+   &zlib_inflate_backend,
+   zlib_deflate_stream_new,
+   zlib_deflate_stream_free,
+   zlib_deflate_define,
+   zlib_deflate_set_in,
+   zlib_set_out,
+   zlib_deflate_trans
+};
+
+const struct trans_stream_backend zlib_inflate_backend = {
+   "zlib_inflate",
+   &zlib_deflate_backend,
+   zlib_inflate_stream_new,
+   zlib_inflate_stream_free,
+   zlib_inflate_define,
+   zlib_inflate_set_in,
+   zlib_set_out,
+   zlib_inflate_trans
+};
diff --git a/deps/libretro-common/string/stdstring.c b/deps/libretro-common/string/stdstring.c
new file mode 100644 (file)
index 0000000..4b36deb
--- /dev/null
@@ -0,0 +1,728 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (stdstring.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <stdint.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <compat/strl.h>
+#include <string/stdstring.h>
+#include <encodings/utf.h>
+
+const uint8_t lr_char_props[256] = {
+       /*x0   x1   x2   x3   x4   x5   x6   x7   x8   x9   xA   xB   xC   xD   xE   xF */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x                  */
+       0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x  !"#$%&'()*+,-./ */
+       0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
+       0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
+       0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
+       0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
+       0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx                  */
+};
+
+char *string_init(const char *src)
+{
+   return src ? strdup(src) : NULL;
+}
+
+void string_set(char **string, const char *src)
+{
+   free(*string);
+   *string = string_init(src);
+}
+
+
+char *string_to_upper(char *s)
+{
+   char *cs = (char *)s;
+   for ( ; *cs != '\0'; cs++)
+      *cs = toupper((unsigned char)*cs);
+   return s;
+}
+
+char *string_to_lower(char *s)
+{
+   char *cs = (char *)s;
+   for ( ; *cs != '\0'; cs++)
+      *cs = tolower((unsigned char)*cs);
+   return s;
+}
+
+char *string_ucwords(char *s)
+{
+   char *cs = (char *)s;
+   for ( ; *cs != '\0'; cs++)
+   {
+      if (*cs == ' ')
+         *(cs+1) = toupper((unsigned char)*(cs+1));
+   }
+
+   s[0] = toupper((unsigned char)s[0]);
+   return s;
+}
+
+char *string_replace_substring(const char *in,
+      const char *pattern, size_t pattern_len,
+      const char *replacement, size_t replacement_len)
+{
+   size_t outlen;
+   size_t numhits     = 0;
+   const char *inat   = NULL;
+   const char *inprev = NULL;
+   char          *out = NULL;
+   char        *outat = NULL;
+
+   /* if either pattern or replacement is NULL,
+    * duplicate in and let caller handle it. */
+   if (!pattern || !replacement)
+      return strdup(in);
+
+   inat            = in;
+
+   while ((inat = strstr(inat, pattern)))
+   {
+      inat += pattern_len;
+      numhits++;
+   }
+
+   outlen          = strlen(in) - pattern_len*numhits + replacement_len*numhits;
+
+   if (!(out = (char *)malloc(outlen+1)))
+      return NULL;
+
+   outat           = out;
+   inat            = in;
+   inprev          = in;
+
+   while ((inat = strstr(inat, pattern)))
+   {
+      memcpy(outat, inprev, inat-inprev);
+      outat += inat-inprev;
+      memcpy(outat, replacement, replacement_len);
+      outat += replacement_len;
+      inat  += pattern_len;
+      inprev = inat;
+   }
+   strcpy(outat, inprev);
+
+   return out;
+}
+
+/**
+ * string_trim_whitespace_left:
+ *
+ * Remove leading whitespaces
+ **/
+char *string_trim_whitespace_left(char *const s)
+{
+   if (s && *s)
+   {
+      size_t len     = strlen(s);
+      char *current  = s;
+
+      while (*current && ISSPACE((unsigned char)*current))
+      {
+         ++current;
+         --len;
+      }
+
+      if (s != current)
+         memmove(s, current, len + 1);
+   }
+
+   return s;
+}
+
+/**
+ * string_trim_whitespace_right:
+ *
+ * Remove trailing whitespaces
+ **/
+char *string_trim_whitespace_right(char *const s)
+{
+   if (s && *s)
+   {
+      size_t len     = strlen(s);
+      char  *current = s + len - 1;
+
+      while (current != s && ISSPACE((unsigned char)*current))
+      {
+         --current;
+         --len;
+      }
+
+      current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
+   }
+
+   return s;
+}
+
+/**
+ * string_trim_whitespace:
+ *
+ * Remove leading and trailing whitespaces
+ **/
+char *string_trim_whitespace(char *const s)
+{
+   string_trim_whitespace_right(s);  /* order matters */
+   string_trim_whitespace_left(s);
+
+   return s;
+}
+
+/**
+ * word_wrap:
+ * @dst                : pointer to destination buffer.
+ * @dst_size           : size of destination buffer.
+ * @src                : pointer to input string.
+ * @line_width         : max number of characters per line.
+ * @wideglyph_width    : not used, but is necessary to keep
+ *                       compatibility with word_wrap_wideglyph().
+ * @max_lines          : max lines of destination string.
+ *                       0 means no limit.
+ *
+ * Wraps string specified by 'src' to destination buffer
+ * specified by 'dst' and 'dst_size'.
+ * This function assumes that all glyphs in the string
+ * have an on-screen pixel width similar to that of
+ * regular Latin characters - i.e. it will not wrap
+ * correctly any text containing so-called 'wide' Unicode
+ * characters (e.g. CJK languages, emojis, etc.).
+ **/
+void word_wrap(
+      char *dst,       size_t dst_size,
+      const char *src, size_t src_len,
+      int line_width,  int wideglyph_width, unsigned max_lines)
+{
+   char *lastspace     = NULL;
+   unsigned counter    = 0;
+   unsigned lines      = 1;
+   const char *src_end = src + src_len;
+
+   /* Prevent buffer overflow */
+   if (dst_size < src_len + 1)
+      return;
+
+   /* Early return if src string length is less
+    * than line width */
+   if (src_len < (size_t)line_width)
+   {
+      strlcpy(dst, src, dst_size);
+      return;
+   }
+
+   while (*src != '\0')
+   {
+      unsigned char_len = (unsigned)(utf8skip(src, 1) - src);
+      counter++;
+
+      if (*src == ' ')
+         lastspace = dst; /* Remember the location of the whitespace */
+      else if (*src == '\n')
+      {
+         /* If newlines embedded in the input,
+          * reset the index */
+         lines++;
+         counter = 0;
+
+         /* Early return if remaining src string
+          * length is less than line width */
+         if (src_end - src <= line_width)
+         {
+            strlcpy(dst, src, dst_size);
+            return;
+         }
+     }
+
+      while (char_len--)
+         *dst++ = *src++;
+
+      if (counter >= (unsigned)line_width)
+      {
+         counter = 0;
+
+         if (lastspace && (max_lines == 0 || lines < max_lines))
+         {
+            /* Replace nearest (previous) whitespace
+             * with newline character */
+            *lastspace = '\n';
+            lines++;
+
+            src -= dst - lastspace - 1;
+            dst = lastspace + 1;
+            lastspace  = NULL;
+
+            /* Early return if remaining src string
+             * length is less than line width */
+            if (src_end - src < line_width)
+            {
+               strlcpy(dst, src, dst_size);
+               return;
+            }
+         }
+      }
+   }
+
+   *dst = '\0';
+}
+
+/**
+ * word_wrap_wideglyph:
+ * @dst                : pointer to destination buffer.
+ * @dst_size           : size of destination buffer.
+ * @src                : pointer to input string.
+ * @line_width         : max number of characters per line.
+ * @wideglyph_width    : effective width of 'wide' Unicode glyphs.
+ *                       the value here is normalised relative to the
+ *                       typical on-screen pixel width of a regular
+ *                       Latin character:
+ *                       - a regular Latin character is defined to
+ *                         have an effective width of 100
+ *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
+ *                       - e.g. if 'wide' Unicode characters in 'src'
+ *                         have an on-screen pixel width twice that of
+ *                         regular Latin characters, wideglyph_width
+ *                         would be 200
+ * @max_lines          : max lines of destination string.
+ *                       0 means no limit.
+ *
+ * Wraps string specified by @src to destination buffer
+ * specified by @dst and @dst_size.
+ * This function assumes that all glyphs in the string
+ * are:
+ * - EITHER 'non-wide' Unicode glyphs, with an on-screen
+ *   pixel width similar to that of regular Latin characters
+ * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
+ *   with an on-screen pixel width defined by @wideglyph_width
+ * Note that wrapping may occur in inappropriate locations
+ * if @src string contains 'wide' Unicode characters whose
+ * on-screen pixel width deviates greatly from the set
+ * @wideglyph_width value.
+ **/
+void word_wrap_wideglyph(char *dst, size_t dst_size,
+      const char *src, size_t src_len, int line_width,
+      int wideglyph_width, unsigned max_lines)
+{
+   char *lastspace                   = NULL;
+   char *lastwideglyph               = NULL;
+   const char *src_end               = src + src_len;
+   unsigned lines                    = 1;
+   /* 'line_width' means max numbers of characters per line,
+    * but this metric is only meaningful when dealing with
+    * 'regular' glyphs that have an on-screen pixel width
+    * similar to that of regular Latin characters.
+    * When handing so-called 'wide' Unicode glyphs, it is
+    * necessary to consider the actual on-screen pixel width
+    * of each character.
+    * In order to do this, we create a distinction between
+    * regular Latin 'non-wide' glyphs and 'wide' glyphs, and
+    * normalise all values relative to the on-screen pixel
+    * width of regular Latin characters:
+    * - Regular 'non-wide' glyphs have a normalised width of 100
+    * - 'line_width' is therefore normalised to 100 * (width_in_characters)
+    * - 'wide' glyphs have a normalised width of
+    *   100 * (wide_character_pixel_width / latin_character_pixel_width)
+    * - When a character is detected, the position in the current
+    *   line is incremented by the regular normalised width of 100
+    * - If that character is then determined to be a 'wide'
+    *   glyph, the position in the current line is further incremented
+    *   by the difference between the normalised 'wide' and 'non-wide'
+    *   width values */
+   unsigned counter_normalized       = 0;
+   int line_width_normalized         = line_width * 100;
+   int additional_counter_normalized = wideglyph_width - 100;
+   /* Early return if src string length is less
+    * than line width */
+   if (src_end - src < line_width)
+   {
+      strlcpy(dst, src, dst_size);
+      return;
+   }
+
+   while (*src != '\0')
+   {
+      unsigned char_len   = (unsigned)(utf8skip(src, 1) - src);
+      counter_normalized += 100;
+
+      /* Prevent buffer overflow */
+      if (char_len >= dst_size)
+         break;
+
+      if (*src == ' ')
+         lastspace          = dst; /* Remember the location of the whitespace */
+      else if (*src == '\n')
+      {
+         /* If newlines embedded in the input,
+          * reset the index */
+         lines++;
+         counter_normalized = 0;
+
+         /* Early return if remaining src string
+          * length is less than line width */
+         if (src_end - src <= line_width)
+         {
+            strlcpy(dst, src, dst_size);
+            return;
+         }
+      }
+      else if (char_len >= 3)
+      {
+         /* Remember the location of the first byte
+          * whose length as UTF-8 >= 3*/
+         lastwideglyph       = dst;
+         counter_normalized += additional_counter_normalized;
+      }
+
+      dst_size -= char_len;
+      while (char_len--)
+         *dst++ = *src++;
+
+      if (counter_normalized >= (unsigned)line_width_normalized)
+      {
+         counter_normalized = 0;
+
+         if (max_lines != 0 && lines >= max_lines)
+            continue;
+         else if (lastwideglyph && (!lastspace || lastwideglyph > lastspace))
+         {
+            /* Insert newline character */
+            *lastwideglyph = '\n';
+            lines++;
+            src           -= dst - lastwideglyph;
+            dst            = lastwideglyph + 1;
+            lastwideglyph  = NULL;
+
+            /* Early return if remaining src string
+             * length is less than line width */
+            if (src_end - src <= line_width)
+            {
+               strlcpy(dst, src, dst_size);
+               return;
+            }
+         }
+         else if (lastspace)
+         {
+            /* Replace nearest (previous) whitespace
+             * with newline character */
+            *lastspace = '\n';
+            lines++;
+            src       -= dst - lastspace - 1;
+            dst        = lastspace + 1;
+            lastspace  = NULL;
+
+            /* Early return if remaining src string
+             * length is less than line width */
+            if (src_end - src < line_width)
+            {
+               strlcpy(dst, src, dst_size);
+               return;
+            }
+         }
+      }
+   }
+
+   *dst = '\0';
+}
+
+/**
+ * string_tokenize:
+ *
+ * Splits string into tokens seperated by @delim
+ * > Returned token string must be free()'d
+ * > Returns NULL if token is not found
+ * > After each call, @str is set to the position after the
+ *   last found token
+ * > Tokens *include* empty strings
+ * Usage example:
+ *    char *str      = "1,2,3,4,5,6,7,,,10,";
+ *    char **str_ptr = &str;
+ *    char *token    = NULL;
+ *    while ((token = string_tokenize(str_ptr, ",")))
+ *    {
+ *        printf("%s\n", token);
+ *        free(token);
+ *        token = NULL;
+ *    }
+ **/
+char* string_tokenize(char **str, const char *delim)
+{
+   /* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
+   char *str_ptr    = NULL;
+   char *delim_ptr  = NULL;
+   char *token      = NULL;
+   size_t token_len = 0;
+
+   /* Sanity checks */
+   if (!str || string_is_empty(delim))
+      return NULL;
+
+
+   /* Note: we don't check string_is_empty() here,
+    * empty strings are valid */
+   if (!(str_ptr = *str))
+      return NULL;
+
+   /* Search for delimiter */
+   if ((delim_ptr = strstr(str_ptr, delim)))
+      token_len = delim_ptr - str_ptr;
+   else
+      token_len = strlen(str_ptr);
+
+   /* Allocate token string */
+   if (!(token = (char *)malloc((token_len + 1) * sizeof(char))))
+      return NULL;
+
+   /* Copy token */
+   strlcpy(token, str_ptr, (token_len + 1) * sizeof(char));
+   token[token_len] = '\0';
+
+   /* Update input string pointer */
+   *str = delim_ptr ? delim_ptr + strlen(delim) : NULL;
+
+   return token;
+}
+
+/**
+ * string_remove_all_chars:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ *
+ * Leaf function.
+ *
+ * Removes every instance of character @c from @str
+ **/
+void string_remove_all_chars(char *str, char c)
+{
+   char *read_ptr  = str;
+   char *write_ptr = str;
+
+   while (*read_ptr != '\0')
+   {
+      *write_ptr = *read_ptr++;
+      if (*write_ptr != c)
+         write_ptr++;
+   }
+
+   *write_ptr = '\0';
+}
+
+/**
+ * string_replace_all_chars:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ * @find               : character to find
+ * @replace            : character to replace @find with
+ *
+ * Replaces every instance of character @find in @str
+ * with character @replace
+ **/
+void string_replace_all_chars(char *str, char find, char replace)
+{
+   char *str_ptr = str;
+   while ((str_ptr = strchr(str_ptr, find)))
+      *str_ptr++ = replace;
+}
+
+/**
+ * string_to_unsigned:
+ * @str                : input string
+ *
+ * Converts string to unsigned integer.
+ *
+ * @return 0 if string is invalid, otherwise > 0
+ **/
+unsigned string_to_unsigned(const char *str)
+{
+   const char *ptr = NULL;
+
+   if (string_is_empty(str))
+      return 0;
+
+   for (ptr = str; *ptr != '\0'; ptr++)
+   {
+      if (!ISDIGIT((unsigned char)*ptr))
+         return 0;
+   }
+
+   return (unsigned)strtoul(str, NULL, 10);
+}
+
+/**
+ * string_hex_to_unsigned:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ *
+ * Converts hexadecimal string to unsigned integer.
+ * Handles optional leading '0x'.
+ *
+ * @return 0 if string is invalid, otherwise > 0
+ **/
+unsigned string_hex_to_unsigned(const char *str)
+{
+   const char *hex_str = str;
+   const char *ptr     = NULL;
+
+   /* Remove leading '0x', if required */
+   if (str[0] != '\0' && str[1] != '\0')
+   {
+      if ( (str[0] == '0') &&
+          ((str[1] == 'x') || 
+           (str[1] == 'X')))
+      {
+         hex_str = str + 2;
+         if (string_is_empty(hex_str))
+            return 0;
+      }
+   }
+   else
+      return 0;
+
+   /* Check for valid characters */
+   for (ptr = hex_str; *ptr != '\0'; ptr++)
+   {
+      if (!isxdigit((unsigned char)*ptr))
+         return 0;
+   }
+
+   return (unsigned)strtoul(hex_str, NULL, 16);
+}
+
+/**
+ * string_count_occurrences_single_character:
+ *
+ * Leaf function.
+ *
+ * Get the total number of occurrences of character @c in @str.
+ *
+ * @return Total number of occurrences of character @c
+ */
+int string_count_occurrences_single_character(const char *str, char c)
+{
+   int count = 0;
+
+   for (; *str; str++)
+      if (*str == c)
+         count++;
+
+   return count;
+}
+
+/**
+ * string_replace_whitespace_with_single_character:
+ * 
+ * Leaf function.
+ *
+ * Replaces all spaces with given character @c.
+ **/
+void string_replace_whitespace_with_single_character(char *str, char c)
+{
+   for (; *str; str++)
+      if (ISSPACE(*str))
+         *str = c;
+}
+
+/**
+ * string_replace_multi_space_with_single_space:
+ *
+ * Leaf function.
+ *
+ * Replaces multiple spaces with a single space in a string.
+ **/
+void string_replace_multi_space_with_single_space(char *str)
+{
+   char *str_trimmed  = str;
+   bool prev_is_space = false;
+   bool curr_is_space = false;
+
+   for (; *str; str++)
+   {
+      curr_is_space  = ISSPACE(*str);
+      if (prev_is_space && curr_is_space)
+         continue;
+      *str_trimmed++ = *str;
+      prev_is_space  = curr_is_space;
+   }
+   *str_trimmed = '\0';
+}
+
+/**
+ * string_remove_all_whitespace:
+ *
+ * Leaf function.
+ *
+ * Remove all spaces from the given string.
+ **/
+void string_remove_all_whitespace(char *str_trimmed, const char *str)
+{
+   for (; *str; str++)
+      if (!ISSPACE(*str))
+         *str_trimmed++ = *str;
+   *str_trimmed = '\0';
+}
+
+/**
+ * Retrieve the last occurance of the given character in a string.
+ */
+int string_index_last_occurance(const char *str, char c)
+{
+   const char *pos = strrchr(str, c);
+   if (pos)
+      return (int)(pos - str);
+   return -1;
+}
+
+/**
+ * string_find_index_substring_string:
+ * @str                : input string (must be non-NULL, otherwise UB)
+ * @substr             : substring to find in @str
+ *
+ * Find the position of substring @substr in string @str.
+ **/
+int string_find_index_substring_string(const char *str, const char *substr)
+{
+   const char *pos = strstr(str, substr);
+   if (pos)
+      return (int)(pos - str);
+   return -1;
+}
+
+/**
+ * string_copy_only_ascii:
+ *
+ * Leaf function.
+ *
+ * Strips non-ASCII characters from a string.
+ **/
+void string_copy_only_ascii(char *str_stripped, const char *str)
+{
+   for (; *str; str++)
+      if (*str > 0x1F && *str < 0x7F)
+         *str_stripped++ = *str;
+   *str_stripped = '\0';
+}
diff --git a/deps/libretro-common/test/hash/test_hash.c b/deps/libretro-common/test/hash/test_hash.c
new file mode 100644 (file)
index 0000000..6065486
--- /dev/null
@@ -0,0 +1,86 @@
+/* Copyright  (C) 2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (test_stdstring.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <check.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <lrc_hash.h>
+
+#define SUITE_NAME "hash"
+
+START_TEST (test_sha256)
+{
+   char output[65];
+   sha256_hash(output, (uint8_t*)"abc", 3);
+   ck_assert(!strcmp(output,
+      "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"));
+}
+END_TEST
+
+START_TEST (test_sha1)
+{
+   char output[41];
+   char tmpfile[512];
+   FILE *fd;
+   tmpnam(tmpfile);
+   fd = fopen(tmpfile, "wb");
+   ck_assert(fd != NULL);
+   fwrite("abc", 1, 3, fd);
+   fclose(fd);
+   sha1_calculate(tmpfile, output);
+
+   ck_assert(!strcmp(output,
+      "A9993E364706816ABA3E25717850C26C9CD0D89D"));
+}
+END_TEST
+
+START_TEST (test_djb2)
+{
+   ck_assert_uint_eq(djb2_calculate("retroarch"), 0xFADF3BCF);
+}
+END_TEST
+
+Suite *create_suite(void)
+{
+   Suite *s = suite_create(SUITE_NAME);
+
+   TCase *tc_core = tcase_create("Core");
+   tcase_add_test(tc_core, test_sha256);
+   tcase_add_test(tc_core, test_sha1);
+   tcase_add_test(tc_core, test_djb2);
+   suite_add_tcase(s, tc_core);
+
+   return s;
+}
+
+int main(void)
+{
+   int num_fail;
+   Suite *s = create_suite();
+   SRunner *sr = srunner_create(s);
+   srunner_run_all(sr, CK_NORMAL);
+   num_fail = srunner_ntests_failed(sr);
+   srunner_free(sr);
+   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/deps/libretro-common/test/lists/test_linked_list.c b/deps/libretro-common/test/lists/test_linked_list.c
new file mode 100644 (file)
index 0000000..5a3b1d4
--- /dev/null
@@ -0,0 +1,1300 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (test_linked_list.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <check.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <lists/linked_list.h>
+
+#define SUITE_NAME "Linked List"
+
+static char *_value_1 = "value1";
+static char *_value_2 = "value2";
+static char *_value_3 = "value3";
+
+START_TEST (test_linked_list_create)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_nonnull(list);
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_free)
+{
+   linked_list_t *queue = linked_list_new();
+   linked_list_free(queue, NULL);
+   linked_list_free(NULL, NULL);
+}
+END_TEST
+
+static int _free_alloced_value_count;
+static void _free_alloced_value(void *value)
+{
+   _free_alloced_value_count++;
+   free(value);
+}
+
+START_TEST (test_linked_list_free_with_fn)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, malloc(1));
+   linked_list_add(list, malloc(1));
+   linked_list_add(list, malloc(1));
+
+   _free_alloced_value_count = 0;
+   linked_list_free(list, &_free_alloced_value);
+
+   ck_assert_int_eq(3, _free_alloced_value_count);
+}
+END_TEST
+
+static void _verify_list(linked_list_t *list, int size, ...)
+{
+   va_list values_list;
+   void **values;
+   int i;
+   linked_list_iterator_t *iterator;
+
+   values = (void **)malloc(size * sizeof(void *));
+
+   ck_assert_int_eq(linked_list_size(list), size);
+
+   va_start(values_list, size);
+   for (i = 0; i < size; i++)
+   {
+      values[i] = va_arg(values_list, void *);
+      ck_assert_ptr_eq(values[i], linked_list_get(list, i));
+   }
+   va_end(values_list);
+
+   iterator = linked_list_iterator(list, true);
+   for (i = 0; i < size; i++)
+   {
+      ck_assert_ptr_nonnull(iterator);
+      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));
+      iterator = linked_list_iterator_next(iterator);
+   }
+   ck_assert_ptr_null(iterator);
+
+   iterator = linked_list_iterator(list, false);
+   for (i = size - 1; i >= 0; i--)
+   {
+      ck_assert_ptr_nonnull(iterator);
+      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));
+      iterator = linked_list_iterator_next(iterator);
+   }
+   ck_assert_ptr_null(iterator);
+
+   free(values);
+}
+
+START_TEST (test_linked_list_add)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_insert_empty)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_insert(list, 0, _value_1);
+
+   ck_assert_int_eq(linked_list_size(list), 1);
+   ck_assert_ptr_eq(linked_list_get(list, 0), _value_1);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_insert_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+   linked_list_insert(list, 0, _value_1);
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_insert_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_3);
+   linked_list_insert(list, 1, _value_2);
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_insert_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_insert(list, 2, _value_3);
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_insert_invalid)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_insert(list, 2, _value_1);
+
+   ck_assert_int_eq(linked_list_size(list), 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_insert_null)
+{
+   linked_list_insert(NULL, 0, _value_1);
+}
+END_TEST
+
+START_TEST (test_linked_list_get_invalid)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_get(list, 2));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_get_null)
+{
+   ck_assert_ptr_null(linked_list_get(NULL, 0));
+}
+END_TEST
+
+START_TEST (test_linked_list_get_first_matching_null)
+{
+   ck_assert_ptr_null(linked_list_get_first_matching(NULL, NULL, NULL));
+}
+END_TEST
+
+START_TEST (test_linked_list_get_first_matching_function_null)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_get_first_matching(list, NULL, NULL));
+
+   linked_list_free(list, NULL);
+}
+
+bool _matches_function(void *value, void *state)
+{
+   ck_assert_ptr_eq(_value_1, state);
+   return value == _value_2;
+}
+
+START_TEST (test_linked_list_get_first_matching_no_match)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_get_first_matching(list, &_matches_function, _value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_get_first_matching_with_match)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(_value_2, linked_list_get_first_matching(list, &_matches_function, _value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_get_last_matching_null)
+{
+   ck_assert_ptr_null(linked_list_get_last_matching(NULL, NULL, NULL));
+}
+END_TEST
+
+START_TEST (test_linked_list_get_last_matching_function_null)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_get_last_matching(list, NULL, NULL));
+
+   linked_list_free(list, NULL);
+}
+
+START_TEST (test_linked_list_get_last_matching_no_match)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_get_last_matching(list, &_matches_function, _value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_get_last_matching_with_match)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(_value_2, linked_list_get_last_matching(list, &_matches_function, _value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_at_null)
+{
+   ck_assert_ptr_null(linked_list_remove_at(NULL, 0));
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_at_empty)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_remove_at(list, 0));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_at_invalid)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   linked_list_remove_at(list, 3);
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_at_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   linked_list_remove_at(list, 0);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_at_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   linked_list_remove_at(list, 1);
+
+   _verify_list(list, 2, _value_1, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_at_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   linked_list_remove_at(list, 2);
+
+   _verify_list(list, 2, _value_1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_at_only)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+
+   linked_list_remove_at(list, 0);
+
+   _verify_list(list, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_null)
+{
+   ck_assert_ptr_null(linked_list_remove_first(NULL, _value_1));
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_empty)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_remove_first(list, _value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_not_found)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_null(linked_list_remove_first(list, "foo"));
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_first(list, _value_2), _value_2);
+
+   _verify_list(list, 2, _value_1, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_first(list, _value_3), _value_3);
+
+   _verify_list(list, 2, _value_1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_only)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);
+
+   _verify_list(list, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_multiple)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_1);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_null)
+{
+   ck_assert_ptr_null(linked_list_remove_last(NULL, _value_1));
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_empty)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_remove_last(list, _value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_not_found)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_null(linked_list_remove_last(list, "foo"));
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_last(list, _value_2), _value_2);
+
+   _verify_list(list, 2, _value_1, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_last(list, _value_3), _value_3);
+
+   _verify_list(list, 2, _value_1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_only)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);
+
+   _verify_list(list, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_multiple)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);
+
+   _verify_list(list, 2, _value_1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_null)
+{
+   ck_assert_ptr_null(linked_list_remove_all(NULL, _value_1));
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_empty)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_remove_all(list, _value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_not_found)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_null(linked_list_remove_all(list, "foo"));
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_all(list, _value_2), _value_2);
+
+   _verify_list(list, 2, _value_1, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_all(list, _value_3), _value_3);
+
+   _verify_list(list, 2, _value_1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_only)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);
+
+   _verify_list(list, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_multiple)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);
+
+   _verify_list(list, 1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+bool _match_value_1(void *value)
+{
+   return _value_1 == value;
+}
+
+bool _no_match(void *value)
+{
+   return false;
+}
+
+START_TEST (test_linked_list_remove_first_matching_null)
+{
+   ck_assert_ptr_null(linked_list_remove_first_matching(NULL, &_match_value_1));
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_matching_empty)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_remove_first_matching(list, &_match_value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_matching_not_found)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_null(linked_list_remove_first_matching(list, &_no_match));
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_matching_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_matching_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_matching_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_matching_only)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_first_matching_multiple)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_1);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_null)
+{
+   ck_assert_ptr_null(linked_list_remove_last_matching(NULL, &_match_value_1));
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_empty)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_ptr_null(linked_list_remove_last_matching(list, &_match_value_1));
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_not_found)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_null(linked_list_remove_last_matching(list, &_no_match));
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_3);
+
+   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_only)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_last_matching_multiple)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+
+   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);
+
+   _verify_list(list, 2, _value_1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_null)
+{
+   linked_list_remove_all_matching(NULL, &_match_value_1);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_empty)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_remove_all_matching(list, &_match_value_1);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_not_found)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   linked_list_remove_all_matching(list, &_no_match);
+
+   _verify_list(list, 3, _value_1, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   linked_list_remove_all_matching(list, &_match_value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_3);
+
+   linked_list_remove_all_matching(list, &_match_value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+   linked_list_add(list, _value_1);
+
+   linked_list_remove_all_matching(list, &_match_value_1);
+
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_only)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+
+   linked_list_remove_all_matching(list, &_match_value_1);
+
+   _verify_list(list, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_remove_all_matching_multiple)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_1);
+
+   linked_list_remove_all_matching(list, &_match_value_1);
+
+   _verify_list(list, 1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_set_at_null)
+{
+   ck_assert_int_eq(linked_list_set_at(NULL, 0, _value_1) == true, 0);
+}
+END_TEST
+
+START_TEST (test_linked_list_set_at_empty)
+{
+   linked_list_t *list = linked_list_new();
+   ck_assert_int_eq(linked_list_set_at(list, 0, _value_1) == true, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_set_at_invalid)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   ck_assert_int_eq(linked_list_set_at(list, 1, _value_2) == true, 0);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+static char *_replacement_value = "foo";
+
+START_TEST (test_linked_list_set_at_first)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_int_eq(linked_list_set_at(list, 0, _replacement_value) == false, 0);
+
+   _verify_list(list, 3, _replacement_value, _value_2, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_set_at_middle)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_int_eq(linked_list_set_at(list, 1, _replacement_value) == false, 0);
+
+   _verify_list(list, 3, _value_1, _replacement_value, _value_3);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_set_at_last)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   ck_assert_int_eq(linked_list_set_at(list, 2, _replacement_value) == false, 0);
+
+   _verify_list(list, 3, _value_1, _value_2, _replacement_value);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_iterator_remove_null)
+{
+   ck_assert_ptr_null(linked_list_iterator_remove(NULL));
+}
+END_TEST
+
+START_TEST (test_linked_list_iterator_remove_first)
+{
+   linked_list_t *list;
+   linked_list_iterator_t *iterator;
+
+   list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   iterator = linked_list_iterator(list, true);
+   iterator = linked_list_iterator_remove(iterator);
+
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_2);
+   _verify_list(list, 2, _value_2, _value_3);
+
+   linked_list_iterator_free(iterator);
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_iterator_remove_middle)
+{
+   linked_list_t *list;
+   linked_list_iterator_t *iterator;
+
+   list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   iterator = linked_list_iterator(list, true);
+   iterator = linked_list_iterator_next(iterator);
+   iterator = linked_list_iterator_remove(iterator);
+
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_3);
+   _verify_list(list, 2, _value_1, _value_3);
+
+   linked_list_iterator_free(iterator);
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_iterator_remove_last)
+{
+   linked_list_t *list;
+   linked_list_iterator_t *iterator;
+
+   list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   iterator = linked_list_iterator(list, true);
+   iterator = linked_list_iterator_next(iterator);
+   iterator = linked_list_iterator_next(iterator);
+   iterator = linked_list_iterator_remove(iterator);
+
+   ck_assert_ptr_null(iterator);
+   _verify_list(list, 2, _value_1, _value_2);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_iterator_free_null)
+{
+   linked_list_iterator_free(NULL);
+}
+END_TEST
+
+static size_t _foreach_count;
+static void _foreach_fn(size_t index, void *value)
+{
+   _foreach_count++;
+}
+
+START_TEST (test_linked_list_foreach_null_list)
+{
+   linked_list_foreach(NULL, _foreach_fn);
+}
+END_TEST
+
+START_TEST (test_linked_list_foreach_null_fn)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   linked_list_foreach(list, NULL);
+
+   linked_list_free(list, NULL);
+}
+END_TEST
+
+START_TEST (test_linked_list_foreach_valid)
+{
+   linked_list_t *list = linked_list_new();
+   linked_list_add(list, _value_1);
+   linked_list_add(list, _value_2);
+   linked_list_add(list, _value_3);
+
+   _foreach_count = 0;
+   linked_list_foreach(list, &_foreach_fn);
+   ck_assert_uint_eq(3, _foreach_count);
+
+   linked_list_free(list, NULL);
+}
+
+Suite *create_suite(void)
+{
+   Suite *s = suite_create(SUITE_NAME);
+
+   TCase *tc_core = tcase_create("Core");
+   tcase_add_test(tc_core, test_linked_list_create);
+   tcase_add_test(tc_core, test_linked_list_free);
+   tcase_add_test(tc_core, test_linked_list_free_with_fn);
+   tcase_add_test(tc_core, test_linked_list_add);
+   tcase_add_test(tc_core, test_linked_list_insert_empty);
+   tcase_add_test(tc_core, test_linked_list_insert_first);
+   tcase_add_test(tc_core, test_linked_list_insert_middle);
+   tcase_add_test(tc_core, test_linked_list_insert_last);
+   tcase_add_test(tc_core, test_linked_list_insert_invalid);
+   tcase_add_test(tc_core, test_linked_list_insert_null);
+   tcase_add_test(tc_core, test_linked_list_get_invalid);
+   tcase_add_test(tc_core, test_linked_list_get_null);
+   tcase_add_test(tc_core, test_linked_list_get_first_matching_null);
+   tcase_add_test(tc_core, test_linked_list_get_first_matching_function_null);
+   tcase_add_test(tc_core, test_linked_list_get_first_matching_no_match);
+   tcase_add_test(tc_core, test_linked_list_get_first_matching_with_match);
+   tcase_add_test(tc_core, test_linked_list_get_last_matching_null);
+   tcase_add_test(tc_core, test_linked_list_get_last_matching_function_null);
+   tcase_add_test(tc_core, test_linked_list_get_last_matching_no_match);
+   tcase_add_test(tc_core, test_linked_list_get_last_matching_with_match);
+   tcase_add_test(tc_core, test_linked_list_remove_at_null);
+   tcase_add_test(tc_core, test_linked_list_remove_at_empty);
+   tcase_add_test(tc_core, test_linked_list_remove_at_invalid);
+   tcase_add_test(tc_core, test_linked_list_remove_at_first);
+   tcase_add_test(tc_core, test_linked_list_remove_at_middle);
+   tcase_add_test(tc_core, test_linked_list_remove_at_last);
+   tcase_add_test(tc_core, test_linked_list_remove_at_only);
+   tcase_add_test(tc_core, test_linked_list_remove_first_null);
+   tcase_add_test(tc_core, test_linked_list_remove_first_empty);
+   tcase_add_test(tc_core, test_linked_list_remove_first_not_found);
+   tcase_add_test(tc_core, test_linked_list_remove_first_first);
+   tcase_add_test(tc_core, test_linked_list_remove_first_middle);
+   tcase_add_test(tc_core, test_linked_list_remove_first_last);
+   tcase_add_test(tc_core, test_linked_list_remove_first_only);
+   tcase_add_test(tc_core, test_linked_list_remove_first_multiple);
+   tcase_add_test(tc_core, test_linked_list_remove_last_null);
+   tcase_add_test(tc_core, test_linked_list_remove_last_empty);
+   tcase_add_test(tc_core, test_linked_list_remove_last_not_found);
+   tcase_add_test(tc_core, test_linked_list_remove_last_first);
+   tcase_add_test(tc_core, test_linked_list_remove_last_middle);
+   tcase_add_test(tc_core, test_linked_list_remove_last_last);
+   tcase_add_test(tc_core, test_linked_list_remove_last_only);
+   tcase_add_test(tc_core, test_linked_list_remove_last_multiple);
+   tcase_add_test(tc_core, test_linked_list_remove_all_null);
+   tcase_add_test(tc_core, test_linked_list_remove_all_empty);
+   tcase_add_test(tc_core, test_linked_list_remove_all_not_found);
+   tcase_add_test(tc_core, test_linked_list_remove_all_first);
+   tcase_add_test(tc_core, test_linked_list_remove_all_middle);
+   tcase_add_test(tc_core, test_linked_list_remove_all_last);
+   tcase_add_test(tc_core, test_linked_list_remove_all_only);
+   tcase_add_test(tc_core, test_linked_list_remove_all_multiple);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_null);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_empty);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_not_found);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_first);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_middle);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_last);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_only);
+   tcase_add_test(tc_core, test_linked_list_remove_first_matching_multiple);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_null);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_empty);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_not_found);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_first);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_middle);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_last);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_only);
+   tcase_add_test(tc_core, test_linked_list_remove_last_matching_multiple);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_null);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_empty);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_not_found);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_first);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_middle);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_last);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_only);
+   tcase_add_test(tc_core, test_linked_list_remove_all_matching_multiple);
+   tcase_add_test(tc_core, test_linked_list_set_at_null);
+   tcase_add_test(tc_core, test_linked_list_set_at_empty);
+   tcase_add_test(tc_core, test_linked_list_set_at_invalid);
+   tcase_add_test(tc_core, test_linked_list_set_at_first);
+   tcase_add_test(tc_core, test_linked_list_set_at_middle);
+   tcase_add_test(tc_core, test_linked_list_set_at_last);
+   tcase_add_test(tc_core, test_linked_list_iterator_remove_null);
+   tcase_add_test(tc_core, test_linked_list_iterator_remove_first);
+   tcase_add_test(tc_core, test_linked_list_iterator_remove_middle);
+   tcase_add_test(tc_core, test_linked_list_iterator_remove_last);
+   tcase_add_test(tc_core, test_linked_list_iterator_free_null);
+   tcase_add_test(tc_core, test_linked_list_foreach_null_list);
+   tcase_add_test(tc_core, test_linked_list_foreach_null_fn);
+   tcase_add_test(tc_core, test_linked_list_foreach_valid);
+   suite_add_tcase(s, tc_core);
+
+   return s;
+}
+
+int main(void)
+{
+   int num_fail;
+   Suite *s = create_suite();
+   SRunner *sr = srunner_create(s);
+   srunner_run_all(sr, CK_NORMAL);
+   num_fail = srunner_ntests_failed(sr);
+   srunner_free(sr);
+   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/deps/libretro-common/test/queues/test_generic_queue.c b/deps/libretro-common/test/queues/test_generic_queue.c
new file mode 100644 (file)
index 0000000..3fe5f0c
--- /dev/null
@@ -0,0 +1,410 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (test_generic_queue.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <check.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <queues/generic_queue.h>
+
+#define SUITE_NAME "Generic Queue"
+
+static char *_value_1 = "value1";
+static char *_value_2 = "value2";
+static char *_value_3 = "value3";
+
+START_TEST (test_generic_queue_create)
+{
+   generic_queue_t *queue = generic_queue_new();
+   ck_assert_ptr_nonnull(queue);
+   generic_queue_free(queue, NULL);
+}
+END_TEST
+
+START_TEST (test_generic_queue_free)
+{
+   generic_queue_t *queue = generic_queue_new();
+   generic_queue_free(queue, NULL);
+   generic_queue_free(NULL, NULL);
+}
+END_TEST
+
+START_TEST (test_generic_queue_push_pop)
+{
+   generic_queue_t *queue;
+   char *value;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   ck_assert_int_eq(generic_queue_length(queue), 1);
+   value = (char *) generic_queue_pop(queue);
+   ck_assert_ptr_eq(value, _value_1);
+   ck_assert_int_eq(generic_queue_length(queue), 0);
+
+   generic_queue_push(queue, _value_2);
+   ck_assert_int_eq(generic_queue_length(queue), 1);
+   generic_queue_push(queue, _value_3);
+   ck_assert_int_eq(generic_queue_length(queue), 2);
+   value = (char *) generic_queue_pop(queue);
+   ck_assert_ptr_eq(value, _value_3);
+   ck_assert_int_eq(generic_queue_length(queue), 1);
+   value = (char *) generic_queue_pop(queue);
+   ck_assert_ptr_eq(value, _value_2);
+   ck_assert_int_eq(generic_queue_length(queue), 0);
+
+   generic_queue_free(queue, NULL);
+}
+END_TEST
+
+START_TEST (test_generic_queue_peek)
+{
+   generic_queue_t *queue;
+
+   queue = generic_queue_new();
+   ck_assert_ptr_null(generic_queue_peek(queue));
+   ck_assert_ptr_null(generic_queue_peek_first(queue));
+
+   generic_queue_push(queue, _value_1);
+   ck_assert_ptr_eq(_value_1, generic_queue_peek(queue));
+   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));
+
+   generic_queue_push(queue, _value_2);
+   ck_assert_ptr_eq(_value_2, generic_queue_peek(queue));
+   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));
+
+   generic_queue_push(queue, _value_3);
+   ck_assert_ptr_eq(_value_3, generic_queue_peek(queue));
+   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));
+
+   generic_queue_free(queue, NULL);
+}
+END_TEST
+
+START_TEST (test_generic_queue_shift_unshift)
+{
+   generic_queue_t *queue;
+   char *value;
+
+   queue = generic_queue_new();
+   generic_queue_shift(queue, _value_1);
+   ck_assert_int_eq(generic_queue_length(queue), 1);
+   value = (char *) generic_queue_unshift(queue);
+   ck_assert_ptr_eq(value, _value_1);
+   ck_assert_int_eq(generic_queue_length(queue), 0);
+
+   generic_queue_shift(queue, _value_2);
+   ck_assert_int_eq(generic_queue_length(queue), 1);
+   generic_queue_shift(queue, _value_3);
+   ck_assert_int_eq(generic_queue_length(queue), 2);
+   value = (char *) generic_queue_unshift(queue);
+   ck_assert_ptr_eq(value, _value_3);
+   ck_assert_int_eq(generic_queue_length(queue), 1);
+   value = (char *) generic_queue_unshift(queue);
+   ck_assert_ptr_eq(value, _value_2);
+   ck_assert_int_eq(generic_queue_length(queue), 0);
+
+   generic_queue_free(queue, NULL);
+}
+END_TEST
+
+START_TEST (test_generic_queue_empty)
+{
+   generic_queue_t *queue;
+
+   queue = generic_queue_new();
+   ck_assert_ptr_null(generic_queue_pop(queue));
+   ck_assert_ptr_null(generic_queue_unshift(queue));
+   generic_queue_free(queue, NULL);
+}
+END_TEST
+
+void _free_value(void *value)
+{
+   return;
+}
+
+START_TEST (test_generic_queue_iterator)
+{
+   generic_queue_t *queue;
+   generic_queue_iterator_t *iterator;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   generic_queue_push(queue, _value_2);
+   generic_queue_push(queue, _value_3);
+
+   iterator = generic_queue_iterator(queue, true);
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);
+   iterator = generic_queue_iterator_next(iterator);
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);
+   iterator = generic_queue_iterator_next(iterator);
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);
+   iterator = generic_queue_iterator_next(iterator);
+   ck_assert_ptr_null(iterator);
+
+   iterator = generic_queue_iterator(queue, false);
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);
+   iterator = generic_queue_iterator_next(iterator);
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);
+   iterator = generic_queue_iterator_next(iterator);
+   ck_assert_ptr_nonnull(iterator);
+   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);
+   iterator = generic_queue_iterator_next(iterator);
+   ck_assert_ptr_null(iterator);
+
+   generic_queue_free(queue, &_free_value);
+}
+END_TEST
+
+START_TEST (test_generic_queue_shift_free)
+{
+   generic_queue_t *queue;
+
+   queue = generic_queue_new();
+
+   generic_queue_shift(queue, _value_1);
+   generic_queue_shift(queue, _value_2);
+   generic_queue_shift(queue, _value_3);
+
+   generic_queue_free(queue, &_free_value);
+}
+END_TEST
+
+START_TEST (test_generic_queue_remove_one)
+{
+   generic_queue_t *queue;
+   generic_queue_iterator_t *iterator;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+
+   iterator = generic_queue_iterator(queue, true);
+   iterator = generic_queue_iterator_remove(iterator);
+   ck_assert_ptr_null(iterator);
+   ck_assert_int_eq(generic_queue_length(queue), 0);
+
+   generic_queue_free(queue, NULL);
+}
+END_TEST
+
+static void _verify_queue_values(generic_queue_t *queue, int count, ...)
+{
+   va_list values_list;
+   void **values;
+   int i;
+   generic_queue_iterator_t *iterator;
+
+   values = (void **)malloc(count * sizeof(void *));
+
+   ck_assert_int_eq(count, generic_queue_length(queue));
+
+   va_start(values_list, count);
+   for (i = 0; i < count; i++)
+      values[i] = va_arg(values_list, void *);
+   va_end(values_list);
+
+   iterator = generic_queue_iterator(queue, true);
+   for (i = 0; i < count; i++)
+   {
+      ck_assert_ptr_nonnull(iterator);
+      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));
+      iterator = generic_queue_iterator_next(iterator);
+   }
+   ck_assert_ptr_null(iterator);
+
+   iterator = generic_queue_iterator(queue, false);
+   for (i = count - 1; i >= 0; i--)
+   {
+      ck_assert_ptr_nonnull(iterator);
+      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));
+      iterator = generic_queue_iterator_next(iterator);
+   }
+   ck_assert_ptr_null(iterator);
+
+   free(values);
+}
+
+START_TEST (test_generic_queue_iterator_remove_first)
+{
+   generic_queue_t *queue;
+   generic_queue_iterator_t *iterator;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   generic_queue_push(queue, _value_2);
+   generic_queue_push(queue, _value_3);
+
+   iterator = generic_queue_iterator(queue, true);
+   iterator = generic_queue_iterator_remove(iterator);
+   generic_queue_iterator_free(iterator);
+
+   _verify_queue_values(queue, 2, _value_2, _value_3);
+
+   generic_queue_free(queue, &_free_value);
+}
+END_TEST
+
+START_TEST (test_generic_queue_iterator_remove_middle)
+{
+   generic_queue_t *queue;
+   generic_queue_iterator_t *iterator;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   generic_queue_push(queue, _value_2);
+   generic_queue_push(queue, _value_3);
+
+   iterator = generic_queue_iterator(queue, true);
+   iterator = generic_queue_iterator_next(iterator);
+   iterator = generic_queue_iterator_remove(iterator);
+   generic_queue_iterator_free(iterator);
+
+   _verify_queue_values(queue, 2, _value_1, _value_3);
+
+   generic_queue_free(queue, &_free_value);
+}
+END_TEST
+
+START_TEST (test_generic_queue_iterator_remove_last)
+{
+   generic_queue_t *queue;
+   generic_queue_iterator_t *iterator;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   generic_queue_push(queue, _value_2);
+   generic_queue_push(queue, _value_3);
+
+   iterator = generic_queue_iterator(queue, false);
+   iterator = generic_queue_iterator_remove(iterator);
+   generic_queue_iterator_free(iterator);
+
+   _verify_queue_values(queue, 2, _value_1, _value_2);
+
+   generic_queue_free(queue, &_free_value);
+}
+END_TEST
+
+START_TEST (test_generic_queue_remove_first)
+{
+   generic_queue_t *queue;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   generic_queue_push(queue, _value_2);
+   generic_queue_push(queue, _value_3);
+
+   ck_assert_ptr_eq(generic_queue_remove(queue, _value_1), _value_1);
+
+   _verify_queue_values(queue, 2, _value_2, _value_3);
+
+   generic_queue_free(queue, &_free_value);
+}
+
+START_TEST (test_generic_queue_remove_middle)
+{
+   generic_queue_t *queue;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   generic_queue_push(queue, _value_2);
+   generic_queue_push(queue, _value_3);
+
+   ck_assert_ptr_eq(generic_queue_remove(queue, _value_2), _value_2);
+
+   _verify_queue_values(queue, 2, _value_1, _value_3);
+
+   generic_queue_free(queue, &_free_value);
+}
+
+START_TEST (test_generic_queue_remove_last)
+{
+   generic_queue_t *queue;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   generic_queue_push(queue, _value_2);
+   generic_queue_push(queue, _value_3);
+
+   ck_assert_ptr_eq(generic_queue_remove(queue, _value_3), _value_3);
+
+   _verify_queue_values(queue, 2, _value_1, _value_2);
+
+   generic_queue_free(queue, &_free_value);
+}
+
+START_TEST (test_generic_queue_iterator_free)
+{
+   generic_queue_t *queue;
+   generic_queue_iterator_t *iterator;
+
+   queue = generic_queue_new();
+   generic_queue_push(queue, _value_1);
+   iterator = generic_queue_iterator(queue, true);
+
+   generic_queue_iterator_free(iterator);
+   generic_queue_iterator_free(NULL);
+
+   generic_queue_free(queue, _free_value);
+}
+END_TEST
+
+Suite *create_suite(void)
+{
+   Suite *s = suite_create(SUITE_NAME);
+
+   TCase *tc_core = tcase_create("Core");
+   tcase_add_test(tc_core, test_generic_queue_create);
+   tcase_add_test(tc_core, test_generic_queue_free);
+   tcase_add_test(tc_core, test_generic_queue_push_pop);
+   tcase_add_test(tc_core, test_generic_queue_peek);
+   tcase_add_test(tc_core, test_generic_queue_shift_unshift);
+   tcase_add_test(tc_core, test_generic_queue_empty);
+   tcase_add_test(tc_core, test_generic_queue_iterator);
+   tcase_add_test(tc_core, test_generic_queue_shift_free);
+   tcase_add_test(tc_core, test_generic_queue_remove_one);
+   tcase_add_test(tc_core, test_generic_queue_iterator_remove_first);
+   tcase_add_test(tc_core, test_generic_queue_iterator_remove_middle);
+   tcase_add_test(tc_core, test_generic_queue_iterator_remove_last);
+   tcase_add_test(tc_core, test_generic_queue_remove_first);
+   tcase_add_test(tc_core, test_generic_queue_remove_middle);
+   tcase_add_test(tc_core, test_generic_queue_remove_last);
+   tcase_add_test(tc_core, test_generic_queue_iterator_free);
+   suite_add_tcase(s, tc_core);
+
+   return s;
+}
+
+int main(void)
+{
+       int num_fail;
+       Suite *s = create_suite();
+       SRunner *sr = srunner_create(s);
+       srunner_run_all(sr, CK_NORMAL);
+       num_fail = srunner_ntests_failed(sr);
+       srunner_free(sr);
+       return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/deps/libretro-common/test/string/test_stdstring.c b/deps/libretro-common/test/string/test_stdstring.c
new file mode 100644 (file)
index 0000000..4250c1f
--- /dev/null
@@ -0,0 +1,321 @@
+/* Copyright  (C) 2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (test_stdstring.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <check.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <string/stdstring.h>
+#include <encodings/utf.h>
+
+#define SUITE_NAME "stdstring"
+
+START_TEST (test_string_filter)
+{
+   char test1[] = "foo bar some string";
+   char test2[] = "";
+   string_remove_all_chars(test1, 's');
+   string_remove_all_chars(test2, '0');
+   string_remove_all_chars(NULL, 'a');
+   ck_assert(!strcmp(test1, "foo bar ome tring"));
+   ck_assert(!strcmp(test2, ""));
+}
+END_TEST
+
+START_TEST (test_string_replace)
+{
+   char test1[] = "foo bar some string";
+   string_replace_all_chars(test1, 's', 'S');
+   string_replace_all_chars(NULL, 'a', 'A');
+   ck_assert(!strcmp(test1, "foo bar Some String"));
+}
+END_TEST
+
+START_TEST (test_string_case)
+{
+   char test1[] = "foo";
+   char test2[] = "01foOo[]_";
+   ck_assert(!strcmp(string_to_upper(test1), "FOO"));
+   ck_assert(!strcmp(string_to_upper(test2), "01FOOO[]_"));
+   ck_assert(!strcmp(string_to_lower(test2), "01fooo[]_"));
+}
+END_TEST
+
+START_TEST (test_string_char_classify)
+{
+   ck_assert(ISSPACE(' '));
+   ck_assert(ISSPACE('\n'));
+   ck_assert(ISSPACE('\r'));
+   ck_assert(ISSPACE('\t'));
+   ck_assert(!ISSPACE('a'));
+
+   ck_assert(ISALPHA('a'));
+   ck_assert(ISALPHA('Z'));
+   ck_assert(!ISALPHA('5'));
+
+   ck_assert(ISALNUM('a'));
+   ck_assert(ISALNUM('Z'));
+   ck_assert(ISALNUM('5'));
+}
+END_TEST
+
+START_TEST (test_string_num_conv)
+{
+   ck_assert_uint_eq(3, string_to_unsigned("3"));
+   ck_assert_uint_eq(2147483647, string_to_unsigned("2147483647"));
+   ck_assert_uint_eq(0, string_to_unsigned("foo"));
+   ck_assert_uint_eq(0, string_to_unsigned("-1"));
+   ck_assert_uint_eq(0, string_to_unsigned(NULL));
+
+   ck_assert_uint_eq(10, string_hex_to_unsigned("0xa"));
+   ck_assert_uint_eq(10, string_hex_to_unsigned("a"));
+   ck_assert_uint_eq(255, string_hex_to_unsigned("FF"));
+   ck_assert_uint_eq(255, string_hex_to_unsigned("0xff"));
+   ck_assert_uint_eq(0, string_hex_to_unsigned("0xfzzf"));
+   ck_assert_uint_eq(0, string_hex_to_unsigned("0x"));
+   ck_assert_uint_eq(0, string_hex_to_unsigned("0xx"));
+   ck_assert_uint_eq(0, string_hex_to_unsigned(NULL));
+}
+END_TEST
+
+START_TEST (test_string_tokenizer)
+{
+   char *testinput = "@@1@@2@@3@@@@9@@@";
+   char **ptr = &testinput;
+   char *token = NULL;
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token != NULL);
+   ck_assert(!strcmp(token, ""));
+   free(token);
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token != NULL);
+   ck_assert(!strcmp(token, "1"));
+   free(token);
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token != NULL);
+   ck_assert(!strcmp(token, "2"));
+   free(token);
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token != NULL);
+   ck_assert(!strcmp(token, "3"));
+   free(token);
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token != NULL);
+   ck_assert(!strcmp(token, ""));
+   free(token);
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token != NULL);
+   ck_assert(!strcmp(token, "9"));
+   free(token);
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token != NULL);
+   ck_assert(!strcmp(token, "@"));
+   free(token);
+   token = string_tokenize(ptr, "@@");
+   ck_assert(token == NULL);
+}
+END_TEST
+
+START_TEST (test_string_replacesubstr)
+{
+   char *res = string_replace_substring("foobaarhellowooorldtest", "oo", "ooo");
+   ck_assert(res != NULL);
+   ck_assert(!strcmp(res, "fooobaarhellowoooorldtest"));
+   free(res);
+}
+END_TEST
+
+START_TEST (test_string_trim)
+{
+   char test1[] = "\t \t\nhey there \n \n";
+   char test2[] = "\t \t\nhey there \n \n";
+   char test3[] = "\t \t\nhey there \n \n";
+   ck_assert(string_trim_whitespace_left(test1) ==  (char*)test1);
+   ck_assert(!strcmp(test1, "hey there \n \n"));
+   ck_assert(string_trim_whitespace_right(test2) ==  (char*)test2);
+   ck_assert(!strcmp(test2, "\t \t\nhey there"));
+   ck_assert(string_trim_whitespace(test3) ==  (char*)test3);
+   ck_assert(!strcmp(test3, "hey there"));
+}
+END_TEST
+
+START_TEST (test_string_comparison)
+{
+   ck_assert(string_is_not_equal_fast("foo", "bar", 3));
+   ck_assert(string_is_equal_fast("foo2", "foo2", 4));
+   ck_assert(!string_is_equal_fast("foo1", "foo2", 4));
+   ck_assert(string_is_equal_fast("foo1", "foo2", 3));
+}
+END_TEST
+
+START_TEST (test_word_wrap)
+{
+   const char *testtxt = (
+      "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam nec "
+      "enim quis orci euismod efficitur at nec arcu. Vivamus imperdiet est "
+      "feugiat massa rhoncus porttitor at vitae ante. Nunc a orci vel ipsum "
+      "tempor posuere sed a lacus. Ut erat odio, ultrices vitae iaculis "
+      "fringilla, iaculis ut eros.\nSed facilisis viverra lectus et "
+      "ullamcorper. Aenean risus ex, ornare eget scelerisque ac, imperdiet eu "
+      "ipsum. Morbi pellentesque erat metus, sit amet aliquet libero rutrum "
+      "et. Integer non ullamcorper tellus.");
+   const char *expected = (
+      "Lorem ipsum dolor sit amet, consectetur\n"
+      "adipiscing elit. Nam nec enim quis orci\n"
+      "euismod efficitur at nec arcu. Vivamus\n"
+      "imperdiet est feugiat massa rhoncus\n"
+      "porttitor at vitae ante. Nunc a orci\n"
+      "vel ipsum tempor posuere sed a lacus.\n"
+      "Ut erat odio, ultrices vitae iaculis\n"
+      "fringilla, iaculis ut eros.\n"
+      "Sed facilisis viverra lectus et\n"
+      "ullamcorper. "
+      "Aenean risus ex, ornare eget scelerisque ac, imperdiet eu ipsum. Morbi "
+      "pellentesque erat metus, sit amet aliquet libero rutrum et. Integer "
+      "non ullamcorper tellus.");
+
+   char output[1024];
+
+   word_wrap(output, sizeof(output), testtxt, strlen(testtxt), 40, 100, 10);
+   ck_assert(!strcmp(output, expected));
+}
+END_TEST
+
+START_TEST (test_strlcpy)
+{
+   char buf1[8];
+   ck_assert_uint_eq(3, strlcpy(buf1, "foo", sizeof(buf1)));
+   ck_assert(!memcmp(buf1, "foo", 4));
+   ck_assert_uint_eq(11, strlcpy(buf1, "foo12345678", sizeof(buf1)));
+   ck_assert(!memcmp(buf1, "foo1234", 8));
+}
+END_TEST
+
+START_TEST (test_strlcat)
+{
+   char buf1[8];
+   buf1[0] = 'f';
+   buf1[1] = '\0';
+   ck_assert_uint_eq(10, strlcat(buf1, "ooooooooo", sizeof(buf1)));
+   ck_assert(!memcmp(buf1, "foooooo\0", 8));
+   ck_assert_uint_eq(13, strlcat(buf1, "123456", sizeof(buf1)));
+   ck_assert(!memcmp(buf1, "foooooo\0", 8));
+}
+END_TEST
+
+START_TEST (test_strldup)
+{
+   char buf1[8] = "foo";
+   char *tv1 = strldup(buf1, 16);
+   char *tv2 = strldup(buf1, 2);
+   ck_assert(tv1 != (char*)buf1);
+   ck_assert(tv2 != (char*)buf1);
+   ck_assert_uint_eq(strlen(tv2), 1);
+   ck_assert(tv2[0] == 'f' && tv2[1] == 0);
+   free(tv1);
+   free(tv2);
+}
+END_TEST
+
+START_TEST (test_utf8_conv_utf32)
+{
+   uint32_t output[12];
+   const char test1[] = "aæ⠻จйγチℝ\xff";
+   ck_assert_uint_eq(8, utf8_conv_utf32(output, 12, test1, strlen(test1)));
+   ck_assert_uint_eq(97, output[0]);
+   ck_assert_uint_eq(230, output[1]);
+   ck_assert_uint_eq(10299, output[2]);
+   ck_assert_uint_eq(3592, output[3]);
+   ck_assert_uint_eq(1081, output[4]);
+   ck_assert_uint_eq(947, output[5]);
+   ck_assert_uint_eq(12481, output[6]);
+   ck_assert_uint_eq(8477, output[7]);
+}
+END_TEST
+
+START_TEST (test_utf8_util)
+{
+   const char *test1 = "aæ⠻จ𠀤";
+   const char **tptr = &test1;
+   char out[64];
+   ck_assert_uint_eq(utf8len(test1), 5);
+   ck_assert_uint_eq(utf8len(NULL), 0);
+   ck_assert(&test1[1 + 2 + 3] == utf8skip(test1, 3));
+
+   ck_assert_uint_eq(97, utf8_walk(tptr));
+   ck_assert_uint_eq(230, utf8_walk(tptr));
+   ck_assert_uint_eq(10299, utf8_walk(tptr));
+   ck_assert_uint_eq(3592, utf8_walk(tptr));
+   ck_assert_uint_eq(131108, utf8_walk(tptr));
+
+   //ck_assert_uint_eq(1, utf8cpy(out, 64, test1, 1));
+}
+END_TEST
+
+START_TEST (test_utf16_conv)
+{
+   const uint16_t test1[] = {0x0061, 0x00e6, 0x283b, 0x0e08, 0xd840, 0xdc24};
+   char out[64];
+   size_t outlen = sizeof(out);
+   ck_assert(utf16_conv_utf8((uint8_t*)out, &outlen, test1, sizeof(test1) / 2));
+   ck_assert_uint_eq(outlen, 13);
+   ck_assert(!memcmp(out, "aæ⠻จ𠀤", 13));
+}
+END_TEST
+
+Suite *create_suite(void)
+{
+   Suite *s = suite_create(SUITE_NAME);
+
+   TCase *tc_core = tcase_create("Core");
+   tcase_add_test(tc_core, test_string_comparison);
+   tcase_add_test(tc_core, test_string_num_conv);
+   tcase_add_test(tc_core, test_string_char_classify);
+   tcase_add_test(tc_core, test_string_case);
+   tcase_add_test(tc_core, test_string_filter);
+   tcase_add_test(tc_core, test_string_replace);
+   tcase_add_test(tc_core, test_string_tokenizer);
+   tcase_add_test(tc_core, test_string_trim);
+   tcase_add_test(tc_core, test_string_replacesubstr);
+   tcase_add_test(tc_core, test_word_wrap);
+   tcase_add_test(tc_core, test_strlcpy);
+   tcase_add_test(tc_core, test_strlcat);
+   tcase_add_test(tc_core, test_strldup);
+   tcase_add_test(tc_core, test_utf8_conv_utf32);
+   tcase_add_test(tc_core, test_utf16_conv);
+   tcase_add_test(tc_core, test_utf8_util);
+   suite_add_tcase(s, tc_core);
+
+   return s;
+}
+
+int main(void)
+{
+   int num_fail;
+   Suite *s = create_suite();
+   SRunner *sr = srunner_create(s);
+   srunner_run_all(sr, CK_NORMAL);
+   num_fail = srunner_ntests_failed(sr);
+   srunner_free(sr);
+   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/deps/libretro-common/test/utils/test_utils.c b/deps/libretro-common/test/utils/test_utils.c
new file mode 100644 (file)
index 0000000..1aaacd4
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright  (C) 2021 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (test_stdstring.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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 <check.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <utils/md5.h>
+#include <encodings/crc32.h>
+#include <streams/file_stream.h>
+
+#define SUITE_NAME "hash"
+
+START_TEST (test_md5)
+{
+   uint8_t output[16];
+   MD5_CTX ctx;
+   MD5_Init(&ctx);
+   MD5_Final(output, &ctx);
+   ck_assert(!memcmp(
+      "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e",
+      output, 16));
+   MD5_Init(&ctx);
+   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
+   MD5_Final(output, &ctx);
+   ck_assert(!memcmp(
+      "\x9e\x10\x7d\x9d\x37\x2b\xb6\x82\x6b\xd8\x1d\x35\x42\xa4\x19\xd6",
+      output, 16));
+   MD5_Init(&ctx);
+   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
+   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
+   MD5_Update(&ctx, "The quick brown fox jumps over the lazy dog", 43);
+   MD5_Final(output, &ctx);
+   ck_assert(!memcmp(
+      "\x4e\x67\xdb\x4a\x7a\x40\x6b\x0c\xfd\xad\xd8\x87\xcd\xe7\x88\x8e",
+      output, 16));
+}
+END_TEST
+
+START_TEST (test_crc32)
+{
+   char buf1[] = "retroarch";
+   char buf2[] = "12345678";
+   char buf3[] = "The quick brown fox jumps over the lazy dog";
+   uint32_t test1 = encoding_crc32(0, (uint8_t*)buf1, strlen(buf1));
+   uint32_t test2 = encoding_crc32(0, (uint8_t*)buf2, strlen(buf2));
+   uint32_t test3 = encoding_crc32(0, (uint8_t*)buf3, strlen(buf3));
+   ck_assert_uint_eq(0x3cae141a, test1);
+   ck_assert_uint_eq(0x9ae0daaf, test2);
+   ck_assert_uint_eq(0x414fa339, test3);
+}
+END_TEST
+
+#define CRC32_BUFFER_SIZE 1048576
+#define CRC32_MAX_MB 64
+
+/**
+ * Calculate a CRC32 from the first part of the given file.
+ * "first part" being the first (CRC32_BUFFER_SIZE * CRC32_MAX_MB)
+ * bytes.
+ *
+ * Returns: the crc32, or 0 if there was an error.
+ */
+static uint32_t file_crc32(uint32_t crc, const char *path)
+{
+   unsigned i;
+   RFILE *file        = NULL;
+   unsigned char *buf = NULL;
+   if (!path)
+      return 0;
+
+   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))
+      return 0;
+
+   if (!(buf = (unsigned char*)malloc(CRC32_BUFFER_SIZE)))
+   {
+      filestream_close(file);
+      return 0;
+   }
+
+   for (i = 0; i < CRC32_MAX_MB; i++)
+   {
+      int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);
+      if (nread < 0)           
+      {
+         free(buf);
+         filestream_close(file);
+         return 0;
+      }
+
+      crc = encoding_crc32(crc, buf, (size_t)nread);
+      if (filestream_eof(file))
+         break;
+   }
+   free(buf);
+   filestream_close(file);
+   return crc;
+}
+
+START_TEST (test_crc32_file)
+{
+   char tmpfile[512];
+   FILE *fd;
+   tmpnam(tmpfile);
+   fd = fopen(tmpfile, "wb");
+   ck_assert(fd != NULL);
+   fwrite("12345678", 1, 8, fd);
+   fclose(fd);
+
+   ck_assert_uint_eq(file_crc32(0, tmpfile), 0x9ae0daaf);
+   /* Error checking */
+   ck_assert_uint_eq(file_crc32(0, "/this/path/should/not/exist"), 0);
+   ck_assert_uint_eq(file_crc32(0, NULL), 0);
+}
+END_TEST
+
+Suite *create_suite(void)
+{
+   Suite *s = suite_create(SUITE_NAME);
+
+   TCase *tc_core = tcase_create("Core");
+   tcase_add_test(tc_core, test_md5);
+   tcase_add_test(tc_core, test_crc32);
+   tcase_add_test(tc_core, test_crc32_file);
+   suite_add_tcase(s, tc_core);
+
+   return s;
+}
+
+int main(void)
+{
+   int num_fail;
+   Suite *s = create_suite();
+   SRunner *sr = srunner_create(s);
+   srunner_run_all(sr, CK_NORMAL);
+   num_fail = srunner_ntests_failed(sr);
+   srunner_free(sr);
+   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/deps/libretro-common/time/rtime.c b/deps/libretro-common/time/rtime.c
new file mode 100644 (file)
index 0000000..fee0dab
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rtime.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * 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.
+ */
+
+#ifdef HAVE_THREADS
+#include <rthreads/rthreads.h>
+#include <stdlib.h>
+#endif
+
+#include <string.h>
+#include <time/rtime.h>
+
+#ifdef HAVE_THREADS
+/* TODO/FIXME - global */
+slock_t *rtime_localtime_lock = NULL;
+#endif
+
+/* Must be called before using rtime_localtime() */
+void rtime_init(void)
+{
+   rtime_deinit();
+#ifdef HAVE_THREADS
+   if (!rtime_localtime_lock)
+      rtime_localtime_lock = slock_new();
+#endif
+}
+
+/* Must be called upon program termination */
+void rtime_deinit(void)
+{
+#ifdef HAVE_THREADS
+   if (rtime_localtime_lock)
+   {
+      slock_free(rtime_localtime_lock);
+      rtime_localtime_lock = NULL;
+   }
+#endif
+}
+
+/* Thread-safe wrapper for localtime() */
+struct tm *rtime_localtime(const time_t *timep, struct tm *result)
+{
+   struct tm *time_info = NULL;
+
+   /* Lock mutex */
+#ifdef HAVE_THREADS
+   slock_lock(rtime_localtime_lock);
+#endif
+
+   time_info = localtime(timep);
+   if (time_info)
+      memcpy(result, time_info, sizeof(struct tm));
+
+   /* Unlock mutex */
+#ifdef HAVE_THREADS
+   slock_unlock(rtime_localtime_lock);
+#endif
+
+   return result;
+}
diff --git a/deps/libretro-common/utils/debugbreak/debugbreak.c b/deps/libretro-common/utils/debugbreak/debugbreak.c
new file mode 100644 (file)
index 0000000..2308120
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+
+#if _WIN32_WINNT < 0x0501
+#error Must target Windows NT 5.0.1 or later for DebugBreakProcess
+#endif
+
+#include <Windows.h>
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/* Compile with this line:
+
+gcc -o debugbreak -mno-cygwin -mthreads debugbreak.c
+
+*/
+
+static char errbuffer[256];
+
+static const char *geterrstr(DWORD errcode)
+{
+size_t skip = 0;
+DWORD chars;
+chars = FormatMessage(
+FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+NULL, errcode, 0, errbuffer, sizeof(errbuffer)-1, 0);
+errbuffer[sizeof(errbuffer)-1] = 0;
+if (chars) {
+while (errbuffer[chars-1] == '\r' || errbuffer[chars-1] == '\n') {
+errbuffer[--chars] = 0;
+}
+}
+if (chars && errbuffer[chars-1] == '.') errbuffer[--chars] = 0;
+if (chars >= 2 && errbuffer[0] == '%' && errbuffer[1] >= '0'
+&& errbuffer[1] <= '9')
+{
+skip = 2;
+while (chars > skip && errbuffer[skip] == ' ') ++skip;
+if (chars >= skip+2 && errbuffer[skip] == 'i'
+&& errbuffer[skip+1] == 's')
+{
+skip += 2;
+while (chars > skip && errbuffer[skip] == ' ') ++skip;
+}
+}
+if (chars > skip && errbuffer[skip] >= 'A' && errbuffer[skip] <= 'Z') {
+errbuffer[skip] += 'a' - 'A';
+}
+return errbuffer+skip;
+}
+
+int main(int argc, char *argv[])
+{
+    HANDLE proc;
+    unsigned proc_id = 0;
+    BOOL break_result;
+
+    if (argc != 2) {
+        printf("Usage: debugbreak process_id_number\n");
+        return 1;
+    }
+    proc_id = (unsigned) strtol(argv[1], NULL, 0);
+    if (proc_id == 0) {
+        printf("Invalid process id %u\n", proc_id);
+        return 1;
+    }
+    proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)proc_id);
+    if (proc == NULL) {
+        DWORD lastError = GetLastError();
+        printf("Failed to open process %u\n", proc_id);
+        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
+            geterrstr(lastError));
+        return 1;
+    }
+    break_result = DebugBreakProcess(proc);
+    if (!break_result) {
+        DWORD lastError = GetLastError();
+        printf("Failed to debug break process %u\n", proc_id);
+        printf("Error code is %lu (%s)\n", (unsigned long)lastError,
+            geterrstr(lastError));
+        CloseHandle(proc);
+        return 1;
+    }
+    printf("DebugBreak sent successfully to process id %u\n", proc_id);
+    CloseHandle(proc);
+    return 0;
+}
+
+/* END debugbreak.c */
diff --git a/deps/libretro-common/utils/djb2.c b/deps/libretro-common/utils/djb2.c
new file mode 100644 (file)
index 0000000..d70f2c8
--- /dev/null
@@ -0,0 +1,26 @@
+/* public domain */
+/* gcc -O3 -o djb2 djb2.c */
+
+#include <stdio.h>
+#include <stdint.h>
+
+static uint32_t djb2(const char* str)
+{
+   const unsigned char* aux = (const unsigned char*)str;
+   uint32_t hash = 5381;
+
+   while (*aux)
+      hash = (hash << 5) + hash + *aux++;
+
+   return hash;
+}
+
+int main(int argc, const char* argv[])
+{
+   int i;
+
+   for (i = 1; i < argc; i++)
+      printf( "0x%08xU: %s\n", djb2( argv[ i ] ), argv[ i ] );
+
+   return 0;
+}
diff --git a/deps/libretro-common/utils/md5.c b/deps/libretro-common/utils/md5.c
new file mode 100644 (file)
index 0000000..5deb03c
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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 <solar at openwall.com>
+ *
+ * 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.
+ */
+#include <lrc_hash.h>
+
+#include <string.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 MD5_F(x, y, z)                 ((z) ^ ((x) & ((y) ^ (z))))
+#define MD5_G(x, y, z)                 ((y) ^ ((z) & ((x) ^ (y))))
+#define MD5_H(x, y, z)                 (((x) ^ (y)) ^ (z))
+#define MD5_H2(x, y, z)                        ((x) ^ ((y) ^ (z)))
+#define MD5_I(x, y, z)                 ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define MD5_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);
+
+/*
+ * MD5_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
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define MD5_SET(n) \
+       (*(MD5_u32plus *)&ptr[(n) * 4])
+#define MD5_GET(n) \
+       MD5_SET(n)
+#else
+#define MD5_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 MD5_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 *MD5_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 */
+               MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7)
+               MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12)
+               MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17)
+               MD5_STEP(MD5_F, b, c, d, a, MD5_SET(3), 0xc1bdceee, 22)
+               MD5_STEP(MD5_F, a, b, c, d, MD5_SET(4), 0xf57c0faf, 7)
+               MD5_STEP(MD5_F, d, a, b, c, MD5_SET(5), 0x4787c62a, 12)
+               MD5_STEP(MD5_F, c, d, a, b, MD5_SET(6), 0xa8304613, 17)
+               MD5_STEP(MD5_F, b, c, d, a, MD5_SET(7), 0xfd469501, 22)
+               MD5_STEP(MD5_F, a, b, c, d, MD5_SET(8), 0x698098d8, 7)
+               MD5_STEP(MD5_F, d, a, b, c, MD5_SET(9), 0x8b44f7af, 12)
+               MD5_STEP(MD5_F, c, d, a, b, MD5_SET(10), 0xffff5bb1, 17)
+               MD5_STEP(MD5_F, b, c, d, a, MD5_SET(11), 0x895cd7be, 22)
+               MD5_STEP(MD5_F, a, b, c, d, MD5_SET(12), 0x6b901122, 7)
+               MD5_STEP(MD5_F, d, a, b, c, MD5_SET(13), 0xfd987193, 12)
+               MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17)
+               MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+               MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5)
+               MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9)
+               MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14)
+               MD5_STEP(MD5_G, b, c, d, a, MD5_GET(0), 0xe9b6c7aa, 20)
+               MD5_STEP(MD5_G, a, b, c, d, MD5_GET(5), 0xd62f105d, 5)
+               MD5_STEP(MD5_G, d, a, b, c, MD5_GET(10), 0x02441453, 9)
+               MD5_STEP(MD5_G, c, d, a, b, MD5_GET(15), 0xd8a1e681, 14)
+               MD5_STEP(MD5_G, b, c, d, a, MD5_GET(4), 0xe7d3fbc8, 20)
+               MD5_STEP(MD5_G, a, b, c, d, MD5_GET(9), 0x21e1cde6, 5)
+               MD5_STEP(MD5_G, d, a, b, c, MD5_GET(14), 0xc33707d6, 9)
+               MD5_STEP(MD5_G, c, d, a, b, MD5_GET(3), 0xf4d50d87, 14)
+               MD5_STEP(MD5_G, b, c, d, a, MD5_GET(8), 0x455a14ed, 20)
+               MD5_STEP(MD5_G, a, b, c, d, MD5_GET(13), 0xa9e3e905, 5)
+               MD5_STEP(MD5_G, d, a, b, c, MD5_GET(2), 0xfcefa3f8, 9)
+               MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14)
+               MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+               MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4)
+               MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11)
+               MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16)
+               MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(14), 0xfde5380c, 23)
+               MD5_STEP(MD5_H, a, b, c, d, MD5_GET(1), 0xa4beea44, 4)
+               MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(4), 0x4bdecfa9, 11)
+               MD5_STEP(MD5_H, c, d, a, b, MD5_GET(7), 0xf6bb4b60, 16)
+               MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(10), 0xbebfbc70, 23)
+               MD5_STEP(MD5_H, a, b, c, d, MD5_GET(13), 0x289b7ec6, 4)
+               MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(0), 0xeaa127fa, 11)
+               MD5_STEP(MD5_H, c, d, a, b, MD5_GET(3), 0xd4ef3085, 16)
+               MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(6), 0x04881d05, 23)
+               MD5_STEP(MD5_H, a, b, c, d, MD5_GET(9), 0xd9d4d039, 4)
+               MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(12), 0xe6db99e5, 11)
+               MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16)
+               MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+               MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6)
+               MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10)
+               MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15)
+               MD5_STEP(MD5_I, b, c, d, a, MD5_GET(5), 0xfc93a039, 21)
+               MD5_STEP(MD5_I, a, b, c, d, MD5_GET(12), 0x655b59c3, 6)
+               MD5_STEP(MD5_I, d, a, b, c, MD5_GET(3), 0x8f0ccc92, 10)
+               MD5_STEP(MD5_I, c, d, a, b, MD5_GET(10), 0xffeff47d, 15)
+               MD5_STEP(MD5_I, b, c, d, a, MD5_GET(1), 0x85845dd1, 21)
+               MD5_STEP(MD5_I, a, b, c, d, MD5_GET(8), 0x6fa87e4f, 6)
+               MD5_STEP(MD5_I, d, a, b, c, MD5_GET(15), 0xfe2ce6e0, 10)
+               MD5_STEP(MD5_I, c, d, a, b, MD5_GET(6), 0xa3014314, 15)
+               MD5_STEP(MD5_I, b, c, d, a, MD5_GET(13), 0x4e0811a1, 21)
+               MD5_STEP(MD5_I, a, b, c, d, MD5_GET(4), 0xf7537e82, 6)
+               MD5_STEP(MD5_I, d, a, b, c, MD5_GET(11), 0xbd3af235, 10)
+               MD5_STEP(MD5_I, c, d, a, b, MD5_GET(2), 0x2ad7d2bb, 15)
+               MD5_STEP(MD5_I, b, c, d, a, MD5_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;
+      MD5_body(ctx, ctx->buffer, 64);
+   }
+
+       if (size >= 64)
+   {
+      data = MD5_body(ctx, data, size & ~(unsigned long)0x3f);
+      size &= 0x3f;
+   }
+
+       memcpy(ctx->buffer, data, size);
+}
+
+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);
+      MD5_body(ctx, ctx->buffer, 64);
+      used = 0;
+      available = 64;
+   }
+
+       memset(&ctx->buffer[used], 0, available - 8);
+
+       ctx->lo <<= 3;
+       ctx->buffer[56] = ctx->lo;
+       ctx->buffer[57] = ctx->lo >> 8;
+       ctx->buffer[58] = ctx->lo >> 16;
+       ctx->buffer[59] = ctx->lo >> 24;
+       ctx->buffer[60] = ctx->hi;
+       ctx->buffer[61] = ctx->hi >> 8;
+       ctx->buffer[62] = ctx->hi >> 16;
+       ctx->buffer[63] = ctx->hi >> 24;
+
+       MD5_body(ctx, ctx->buffer, 64);
+
+       result[0] = ctx->a;
+       result[1] = ctx->a >> 8;
+       result[2] = ctx->a >> 16;
+       result[3] = ctx->a >> 24;
+       result[4] = ctx->b;
+       result[5] = ctx->b >> 8;
+       result[6] = ctx->b >> 16;
+       result[7] = ctx->b >> 24;
+       result[8] = ctx->c;
+       result[9] = ctx->c >> 8;
+       result[10] = ctx->c >> 16;
+       result[11] = ctx->c >> 24;
+       result[12] = ctx->d;
+       result[13] = ctx->d >> 8;
+       result[14] = ctx->d >> 16;
+       result[15] = ctx->d >> 24;
+
+       memset(ctx, 0, sizeof(*ctx));
+}
diff --git a/deps/libretro-common/utils/sha1.c b/deps/libretro-common/utils/sha1.c
new file mode 100644 (file)
index 0000000..3c743cb
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ *  sha1.h
+ *
+ *  Copyright (C) 1998, 2009
+ *  Paul E. Jones <paulej@packetizer.com>
+ *  All Rights Reserved
+ *
+ *****************************************************************************
+ *  $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
+ *****************************************************************************
+ *
+ *  Description:
+ *      This class implements the Secure Hashing Standard as defined
+ *      in FIPS PUB 180-1 published April 17, 1995.
+ *
+ *      Many of the variable names in the SHA1Context, especially the
+ *      single character names, were used because those were the names
+ *      used in the publication.
+ *
+ *      Please read the file sha1.c for more information.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include <string/stdstring.h>
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+/*
+ *  This structure will hold context information for the hashing
+ *  operation
+ */
+typedef struct SHA1Context
+{
+   unsigned Message_Digest[5]; /* Message Digest (output)          */
+
+   unsigned Length_Low;        /* Message length in bits           */
+   unsigned Length_High;       /* Message length in bits           */
+
+   unsigned char Message_Block[64]; /* 512-bit message blocks      */
+   int Message_Block_Index;    /* Index into message block array   */
+
+   int Computed;               /* Is the digest computed?          */
+   int Corrupted;              /* Is the message digest corruped?  */
+} SHA1Context;
+
+/*
+ *  Function Prototypes
+ */
+void SHA1Reset(SHA1Context *);
+int SHA1Result(SHA1Context *);
+void SHA1Input( SHA1Context *,
+      const unsigned char *,
+      unsigned);
+
+#endif
+
+/*
+ *  sha1.c
+ *
+ *  Copyright (C) 1998, 2009
+ *  Paul E. Jones <paulej@packetizer.com>
+ *  All Rights Reserved
+ *
+ *****************************************************************************
+ *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $
+ *****************************************************************************
+ *
+ *  Description:
+ *      This file implements the Secure Hashing Standard as defined
+ *      in FIPS PUB 180-1 published April 17, 1995.
+ *
+ *      The Secure Hashing Standard, which uses the Secure Hashing
+ *      Algorithm (SHA), produces a 160-bit message digest for a
+ *      given data stream.  In theory, it is highly improbable that
+ *      two messages will produce the same message digest.  Therefore,
+ *      this algorithm can serve as a means of providing a "fingerprint"
+ *      for a message.
+ *
+ *  Portability Issues:
+ *      SHA-1 is defined in terms of 32-bit "words".  This code was
+ *      written with the expectation that the processor has at least
+ *      a 32-bit machine word size.  If the machine word size is larger,
+ *      the code should still function properly.  One caveat to that
+ *      is that the input functions taking characters and character
+ *      arrays assume that only 8 bits of information are stored in each
+ *      character.
+ *
+ *  Caveats:
+ *      SHA-1 is designed to work with messages less than 2^64 bits
+ *      long. Although SHA-1 allows a message digest to be generated for
+ *      messages of any number of bits less than 2^64, this
+ *      implementation only works with messages with a length that is a
+ *      multiple of the size of an 8-bit character.
+ *
+ */
+
+/*#include "sha1.h"*/
+
+/*
+ *  Define the circular shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+                ((((word) << (bits)) & 0xFFFFFFFF) | \
+                ((word) >> (32-(bits))))
+
+/* Function prototypes */
+void SHA1ProcessMessageBlock(SHA1Context *);
+void SHA1PadMessage(SHA1Context *);
+
+/*
+ *  SHA1Reset
+ *
+ *  Description:
+ *      This function will initialize the SHA1Context in preparation
+ *      for computing a new message digest.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to reset.
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *
+ */
+void SHA1Reset(SHA1Context *context)
+{
+   context->Length_Low             = 0;
+   context->Length_High            = 0;
+   context->Message_Block_Index    = 0;
+
+   context->Message_Digest[0]      = 0x67452301;
+   context->Message_Digest[1]      = 0xEFCDAB89;
+   context->Message_Digest[2]      = 0x98BADCFE;
+   context->Message_Digest[3]      = 0x10325476;
+   context->Message_Digest[4]      = 0xC3D2E1F0;
+
+   context->Computed   = 0;
+   context->Corrupted  = 0;
+}
+
+/*
+ *  SHA1Result
+ *
+ *  Description:
+ *      This function will return the 160-bit message digest into the
+ *      Message_Digest array within the SHA1Context provided
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to use to calculate the SHA-1 hash.
+ *
+ *  Returns:
+ *      1 if successful, 0 if it failed.
+ *
+ *  Comments:
+ *
+ */
+int SHA1Result(SHA1Context *context)
+{
+   if (context->Corrupted)
+      return 0;
+
+   if (!context->Computed)
+   {
+      SHA1PadMessage(context);
+      context->Computed = 1;
+   }
+
+   return 1;
+}
+
+/*
+ *  SHA1Input
+ *
+ *  Description:
+ *      This function accepts an array of octets as the next portion of
+ *      the message.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The SHA-1 context to update
+ *      message_array: [in]
+ *          An array of characters representing the next portion of the
+ *          message.
+ *      length: [in]
+ *          The length of the message in message_array
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *
+ */
+void SHA1Input(     SHA1Context         *context,
+                    const unsigned char *message_array,
+                    unsigned            length)
+{
+   if (!length)
+      return;
+
+   if (context->Computed || context->Corrupted)
+   {
+      context->Corrupted = 1;
+      return;
+   }
+
+   while(length-- && !context->Corrupted)
+   {
+      context->Message_Block[context->Message_Block_Index++] =
+         (*message_array & 0xFF);
+
+      context->Length_Low += 8;
+      /* Force it to 32 bits */
+      context->Length_Low &= 0xFFFFFFFF;
+      if (context->Length_Low == 0)
+      {
+         context->Length_High++;
+         /* Force it to 32 bits */
+         context->Length_High &= 0xFFFFFFFF;
+         if (context->Length_High == 0)
+         {
+            /* Message is too long */
+            context->Corrupted = 1;
+         }
+      }
+
+      if (context->Message_Block_Index == 64)
+         SHA1ProcessMessageBlock(context);
+
+      message_array++;
+   }
+}
+
+/*
+ *  SHA1ProcessMessageBlock
+ *
+ *  Description:
+ *      This function will process the next 512 bits of the message
+ *      stored in the Message_Block array.
+ *
+ *  Parameters:
+ *      None.
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *      Many of the variable names in the SHAContext, especially the
+ *      single character names, were used because those were the names
+ *      used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock(SHA1Context *context)
+{
+   const unsigned K[] =            /* Constants defined in SHA-1   */
+   {
+      0x5A827999,
+      0x6ED9EBA1,
+      0x8F1BBCDC,
+      0xCA62C1D6
+   };
+   int         t;                  /* Loop counter                 */
+   unsigned    temp;               /* Temporary word value         */
+   unsigned    W[80];              /* Word sequence                */
+   unsigned    A, B, C, D, E;      /* Word buffers                 */
+
+   /*
+    *  Initialize the first 16 words in the array W
+    */
+   for (t = 0; t < 16; t++)
+   {
+      W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
+      W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
+      W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;
+      W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
+   }
+
+   for (t = 16; t < 80; t++)
+      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+
+   A = context->Message_Digest[0];
+   B = context->Message_Digest[1];
+   C = context->Message_Digest[2];
+   D = context->Message_Digest[3];
+   E = context->Message_Digest[4];
+
+   for (t = 0; t < 20; t++)
+   {
+      temp =  SHA1CircularShift(5,A) +
+         ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+      temp &= 0xFFFFFFFF;
+      E = D;
+      D = C;
+      C = SHA1CircularShift(30,B);
+      B = A;
+      A = temp;
+   }
+
+   for (t = 20; t < 40; t++)
+   {
+      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+      temp &= 0xFFFFFFFF;
+      E = D;
+      D = C;
+      C = SHA1CircularShift(30,B);
+      B = A;
+      A = temp;
+   }
+
+   for (t = 40; t < 60; t++)
+   {
+      temp = SHA1CircularShift(5,A) +
+         ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+      temp &= 0xFFFFFFFF;
+      E = D;
+      D = C;
+      C = SHA1CircularShift(30,B);
+      B = A;
+      A = temp;
+   }
+
+   for (t = 60; t < 80; t++)
+   {
+      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+      temp &= 0xFFFFFFFF;
+      E = D;
+      D = C;
+      C = SHA1CircularShift(30,B);
+      B = A;
+      A = temp;
+   }
+
+   context->Message_Digest[0] =
+      (context->Message_Digest[0] + A) & 0xFFFFFFFF;
+   context->Message_Digest[1] =
+      (context->Message_Digest[1] + B) & 0xFFFFFFFF;
+   context->Message_Digest[2] =
+      (context->Message_Digest[2] + C) & 0xFFFFFFFF;
+   context->Message_Digest[3] =
+      (context->Message_Digest[3] + D) & 0xFFFFFFFF;
+   context->Message_Digest[4] =
+      (context->Message_Digest[4] + E) & 0xFFFFFFFF;
+
+   context->Message_Block_Index = 0;
+}
+
+/*
+ *  SHA1PadMessage
+ *
+ *  Description:
+ *      According to the standard, the message must be padded to an even
+ *      512 bits.  The first padding bit must be a '1'.  The last 64
+ *      bits represent the length of the original message.  All bits in
+ *      between should be 0.  This function will pad the message
+ *      according to those rules by filling the Message_Block array
+ *      accordingly.  It will also call SHA1ProcessMessageBlock()
+ *      appropriately.  When it returns, it can be assumed that the
+ *      message digest has been computed.
+ *
+ *  Parameters:
+ *      context: [in/out]
+ *          The context to pad
+ *
+ *  Returns:
+ *      Nothing.
+ *
+ *  Comments:
+ *
+ */
+void SHA1PadMessage(SHA1Context *context)
+{
+   /*
+    *  Check to see if the current message block is too small to hold
+    *  the initial padding bits and length.  If so, we will pad the
+    *  block, process it, and then continue padding into a second
+    *  block.
+    */
+   if (context->Message_Block_Index > 55)
+   {
+      context->Message_Block[context->Message_Block_Index++] = 0x80;
+      while(context->Message_Block_Index < 64)
+         context->Message_Block[context->Message_Block_Index++] = 0;
+
+      SHA1ProcessMessageBlock(context);
+
+      while(context->Message_Block_Index < 56)
+         context->Message_Block[context->Message_Block_Index++] = 0;
+   }
+   else
+   {
+      context->Message_Block[context->Message_Block_Index++] = 0x80;
+      while(context->Message_Block_Index < 56)
+         context->Message_Block[context->Message_Block_Index++] = 0;
+   }
+
+   /*
+    *  Store the message length as the last 8 octets
+    */
+   context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
+   context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
+   context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
+   context->Message_Block[59] = (context->Length_High) & 0xFF;
+   context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
+   context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
+   context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
+   context->Message_Block[63] = (context->Length_Low) & 0xFF;
+
+   SHA1ProcessMessageBlock(context);
+}
diff --git a/deps/libretro-common/vfs/vfs_implementation.c b/deps/libretro-common/vfs/vfs_implementation.c
new file mode 100644 (file)
index 0000000..b74716e
--- /dev/null
@@ -0,0 +1,1246 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation.c).
+* ---------------------------------------------------------------------------------------
+*
+* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <string/stdstring.h> /* string_is_empty */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(_WIN32)
+#  ifdef _MSC_VER
+#    define setmode _setmode
+#  endif
+#include <sys/stat.h>
+#  ifdef _XBOX
+#    include <xtl.h>
+#    define INVALID_FILE_ATTRIBUTES -1
+#  else
+
+#    include <fcntl.h>
+#    include <direct.h>
+#    include <windows.h>
+#  endif
+#    include <io.h>
+#else
+#  if defined(PSP)
+#    include <pspiofilemgr.h>
+#  endif
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  if !defined(VITA)
+#  include <dirent.h>
+#  endif
+#  include <unistd.h>
+#  if defined(WIIU)
+#  include <malloc.h>
+#  endif
+#endif
+
+#include <fcntl.h>
+
+/* TODO: Some things are duplicated but I'm really afraid of breaking other platforms by touching this */
+#if defined(VITA)
+#  include <psp2/io/fcntl.h>
+#  include <psp2/io/dirent.h>
+#  include <psp2/io/stat.h>
+#elif !defined(_WIN32)
+#  if defined(PSP)
+#    include <pspiofilemgr.h>
+#  endif
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  include <dirent.h>
+#  include <unistd.h>
+#endif
+
+#if defined(__QNX__) || defined(PSP)
+#include <unistd.h> /* stat() is defined here */
+#endif
+
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+#ifdef __HAIKU__
+#include <kernel/image.h>
+#endif
+#ifndef __MACH__
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+#endif
+#include <compat/strcasestr.h>
+#include <retro_miscellaneous.h>
+#include <encodings/utf.h>
+
+#if defined(_WIN32)
+#ifndef _XBOX
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+#endif
+#elif defined(VITA)
+#define SCE_ERROR_ERRNO_EEXIST 0x80010011
+#include <psp2/io/fcntl.h>
+#include <psp2/io/dirent.h>
+#include <psp2/io/stat.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+
+#if defined(PSP)
+#include <pspkernel.h>
+#endif
+
+#if defined(__PS3__) || defined(__PSL1GHT__)
+#define FS_SUCCEEDED 0
+#define FS_TYPE_DIR 1
+#ifdef __PSL1GHT__
+#include <lv2/sysfs.h>
+#ifndef O_RDONLY
+#define O_RDONLY SYS_O_RDONLY
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY SYS_O_WRONLY
+#endif
+#ifndef O_CREAT
+#define O_CREAT SYS_O_CREAT
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC SYS_O_TRUNC
+#endif
+#ifndef O_RDWR
+#define O_RDWR SYS_O_RDWR
+#endif
+#else
+#include <cell/cell_fs.h>
+#ifndef O_RDONLY
+#define O_RDONLY CELL_FS_O_RDONLY
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY CELL_FS_O_WRONLY
+#endif
+#ifndef O_CREAT
+#define O_CREAT CELL_FS_O_CREAT
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC CELL_FS_O_TRUNC
+#endif
+#ifndef O_RDWR
+#define O_RDWR CELL_FS_O_RDWR
+#endif
+#ifndef sysFsStat
+#define sysFsStat cellFsStat
+#endif
+#ifndef sysFSDirent
+#define sysFSDirent CellFsDirent
+#endif
+#ifndef sysFsOpendir
+#define sysFsOpendir cellFsOpendir
+#endif
+#ifndef sysFsReaddir
+#define sysFsReaddir cellFsReaddir
+#endif
+#ifndef sysFSDirent
+#define sysFSDirent CellFsDirent
+#endif
+#ifndef sysFsClosedir
+#define sysFsClosedir cellFsClosedir
+#endif
+#endif
+#endif
+
+#if defined(VITA)
+#define FIO_S_ISDIR SCE_S_ISDIR
+#endif
+
+#if defined(__QNX__) || defined(PSP)
+#include <unistd.h> /* stat() is defined here */
+#endif
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+
+#endif
+
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define ATLEAST_VC2005
+#endif
+#endif
+
+#include <vfs/vfs_implementation.h>
+#include <libretro.h>
+#if defined(HAVE_MMAP)
+#include <memmap.h>
+#endif
+#include <encodings/utf.h>
+#include <compat/fopen_utf8.h>
+#include <file/file_path.h>
+
+#ifdef HAVE_CDROM
+#include <vfs/vfs_implementation_cdrom.h>
+#endif
+
+#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
+#ifndef HAVE_64BIT_OFFSETS
+#define HAVE_64BIT_OFFSETS
+#endif
+#endif
+
+#define RFILE_HINT_UNBUFFERED (1 << 8)
+
+int64_t retro_vfs_file_seek_internal(
+      libretro_vfs_implementation_file *stream,
+      int64_t offset, int whence)
+{
+   if (!stream)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+         return retro_vfs_file_seek_cdrom(stream, offset, whence);
+#endif
+#ifdef ATLEAST_VC2005
+      /* VC2005 and up have a special 64-bit fseek */
+      return _fseeki64(stream->fp, offset, whence);
+#elif defined(HAVE_64BIT_OFFSETS)
+      return fseeko(stream->fp, (off_t)offset, whence);
+#else
+      return fseek(stream->fp, (long)offset, whence);
+#endif
+   }
+#ifdef HAVE_MMAP
+   /* Need to check stream->mapped because this function is
+    * called in filestream_open() */
+   if (stream->mapped && stream->hints &
+         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+   {
+      /* fseek() returns error on under/overflow but
+       * allows cursor > EOF for
+       read-only file descriptors. */
+      switch (whence)
+      {
+         case SEEK_SET:
+            if (offset < 0)
+               return -1;
+
+            stream->mappos = offset;
+            break;
+
+         case SEEK_CUR:
+            if (  (offset < 0 && stream->mappos + offset > stream->mappos) ||
+                  (offset > 0 && stream->mappos + offset < stream->mappos))
+               return -1;
+
+            stream->mappos += offset;
+            break;
+
+         case SEEK_END:
+            if (stream->mapsize + offset < stream->mapsize)
+               return -1;
+
+            stream->mappos = stream->mapsize + offset;
+            break;
+      }
+      return stream->mappos;
+   }
+#endif
+
+   if (lseek(stream->fd, (off_t)offset, whence) < 0)
+      return -1;
+
+   return 0;
+}
+
+/**
+ * retro_vfs_file_open_impl:
+ * @path               : path to file
+ * @mode               : file mode to use when opening (read/write)
+ * @hints              :
+ *
+ * Opens a file for reading or writing, depending on the requested mode.
+ * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
+ **/
+
+libretro_vfs_implementation_file *retro_vfs_file_open_impl(
+      const char *path, unsigned mode, unsigned hints)
+{
+   int                                flags = 0;
+   const char                     *mode_str = NULL;
+   libretro_vfs_implementation_file *stream = 
+      (libretro_vfs_implementation_file*)
+      malloc(sizeof(*stream));
+
+   if (!stream)
+      return NULL;
+
+   stream->fd                     = 0;
+   stream->hints                  = hints;
+   stream->size                   = 0;
+   stream->buf                    = NULL;
+   stream->fp                     = NULL;
+#ifdef _WIN32
+   stream->fh                     = 0;
+#endif
+   stream->orig_path              = NULL;
+   stream->mappos                 = 0;
+   stream->mapsize                = 0;
+   stream->mapped                 = NULL;
+   stream->scheme                 = VFS_SCHEME_NONE;
+
+#ifdef VFS_FRONTEND
+   if (     path
+         && path[0] == 'v'
+         && path[1] == 'f'
+         && path[2] == 's'
+         && path[3] == 'o'
+         && path[4] == 'n'
+         && path[5] == 'l'
+         && path[6] == 'y'
+         && path[7] == ':'
+         && path[8] == '/'
+         && path[9] == '/')
+         path             += sizeof("vfsonly://")-1;
+#endif
+
+#ifdef HAVE_CDROM
+   stream->cdrom.cue_buf          = NULL;
+   stream->cdrom.cue_len          = 0;
+   stream->cdrom.byte_pos         = 0;
+   stream->cdrom.drive            = 0;
+   stream->cdrom.cur_min          = 0;
+   stream->cdrom.cur_sec          = 0;
+   stream->cdrom.cur_frame        = 0;
+   stream->cdrom.cur_track        = 0;
+   stream->cdrom.cur_lba          = 0;
+   stream->cdrom.last_frame_lba   = 0;
+   stream->cdrom.last_frame[0]    = '\0';
+   stream->cdrom.last_frame_valid = false;
+
+   if (     path
+         && path[0] == 'c'
+         && path[1] == 'd'
+         && path[2] == 'r'
+         && path[3] == 'o'
+         && path[4] == 'm'
+         && path[5] == ':'
+         && path[6] == '/'
+         && path[7] == '/'
+         && path[8] != '\0')
+   {
+      path             += sizeof("cdrom://")-1;
+      stream->scheme    = VFS_SCHEME_CDROM;
+   }
+#endif
+
+   stream->orig_path       = strdup(path);
+
+#ifdef HAVE_MMAP
+   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS && mode == RETRO_VFS_FILE_ACCESS_READ)
+      stream->hints |= RFILE_HINT_UNBUFFERED;
+   else
+#endif
+      stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
+
+   switch (mode)
+   {
+      case RETRO_VFS_FILE_ACCESS_READ:
+         mode_str = "rb";
+
+         flags    = O_RDONLY;
+#ifdef _WIN32
+         flags   |= O_BINARY;
+#endif
+         break;
+
+      case RETRO_VFS_FILE_ACCESS_WRITE:
+         mode_str = "wb";
+
+         flags    = O_WRONLY | O_CREAT | O_TRUNC;
+#if !defined(_WIN32)
+         flags   |= S_IRUSR | S_IWUSR;
+#else
+         flags   |= O_BINARY;
+#endif
+         break;
+
+      case RETRO_VFS_FILE_ACCESS_READ_WRITE:
+         mode_str = "w+b";
+         flags    = O_RDWR | O_CREAT | O_TRUNC;
+#if !defined(_WIN32)
+         flags   |= S_IRUSR | S_IWUSR;
+#else
+         flags   |= O_BINARY;
+#endif
+         break;
+
+      case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
+      case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
+         mode_str = "r+b";
+
+         flags    = O_RDWR;
+#if !defined(_WIN32)
+         flags   |= S_IRUSR | S_IWUSR;
+#else
+         flags   |= O_BINARY;
+#endif
+         break;
+
+      default:
+         goto error;
+   }
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+      FILE *fp;
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+      {
+         retro_vfs_file_open_cdrom(stream, path, mode, hints);
+#if defined(_WIN32) && !defined(_XBOX)
+         if (!stream->fh)
+            goto error;
+#else
+         if (!stream->fp)
+            goto error;
+#endif
+      }
+      else
+#endif
+      {
+         if (!(fp = (FILE*)fopen_utf8(path, mode_str)))
+            goto error;
+
+         stream->fp  = fp;
+      }
+
+      /* Regarding setvbuf:
+       *
+       * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
+       *
+       * If the size argument is not zero but buf is NULL, 
+       * a buffer of the given size will be allocated immediately, and
+       * released on close. This is an extension to ANSI C.
+       *
+       * Since C89 does not support specifying a NULL buffer 
+       * with a non-zero size, we create and track our own buffer for it.
+       */
+      /* TODO: this is only useful for a few platforms, 
+       * find which and add ifdef */
+#if defined(_3DS)
+      if (stream->scheme != VFS_SCHEME_CDROM)
+      {
+         stream->buf = (char*)calloc(1, 0x10000);
+         if (stream->fp)
+            setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000);
+      }
+#elif defined(WIIU)
+      if (stream->scheme != VFS_SCHEME_CDROM)
+      {
+         const int bufsize = 128 * 1024;
+         stream->buf = (char*)memalign(0x40, bufsize);
+         if (stream->fp)
+            setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);
+         stream->buf = (char*)calloc(1, 0x4000);
+         if (stream->fp)
+            setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
+      }
+#endif
+   }
+   else
+   {
+#if defined(_WIN32) && !defined(_XBOX)
+#if defined(LEGACY_WIN32)
+      char *path_local    = utf8_to_local_string_alloc(path);
+      stream->fd          = open(path_local, flags, 0);
+      if (path_local)
+         free(path_local);
+#else
+      wchar_t * path_wide = utf8_to_utf16_string_alloc(path);
+      stream->fd          = _wopen(path_wide, flags, 0);
+      if (path_wide)
+         free(path_wide);
+#endif
+#else
+      stream->fd          = open(path, flags, 0);
+#endif
+
+      if (stream->fd == -1)
+         goto error;
+
+#ifdef HAVE_MMAP
+      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+      {
+         stream->mappos  = 0;
+         stream->mapped  = NULL;
+         stream->mapsize = retro_vfs_file_seek_internal(stream, 0, SEEK_END);
+
+         if (stream->mapsize == (uint64_t)-1)
+            goto error;
+
+         retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+
+         if ((stream->mapped = (uint8_t*)mmap((void*)0,
+               stream->mapsize, PROT_READ,  MAP_SHARED, stream->fd, 0)) == MAP_FAILED)
+            stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
+      }
+#endif
+   }
+#ifdef HAVE_CDROM
+   if (stream->scheme == VFS_SCHEME_CDROM)
+   {
+      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
+      retro_vfs_file_seek_cdrom(stream, 0, SEEK_END);
+
+      stream->size = retro_vfs_file_tell_impl(stream);
+
+      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
+   }
+   else
+#endif
+   {
+      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+      retro_vfs_file_seek_internal(stream, 0, SEEK_END);
+
+      stream->size = retro_vfs_file_tell_impl(stream);
+
+      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+   }
+   return stream;
+
+error:
+   retro_vfs_file_close_impl(stream);
+   return NULL;
+}
+
+int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
+{
+   if (!stream)
+      return -1;
+
+#ifdef HAVE_CDROM
+   if (stream->scheme == VFS_SCHEME_CDROM)
+   {
+      retro_vfs_file_close_cdrom(stream);
+      goto end;
+   }
+#endif
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+      if (stream->fp)
+         fclose(stream->fp);
+   }
+   else
+   {
+#ifdef HAVE_MMAP
+      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+         munmap(stream->mapped, stream->mapsize);
+#endif
+   }
+
+   if (stream->fd > 0)
+      close(stream->fd);
+#ifdef HAVE_CDROM
+end:
+   if (stream->cdrom.cue_buf)
+      free(stream->cdrom.cue_buf);
+#endif
+   if (stream->buf)
+      free(stream->buf);
+
+   if (stream->orig_path)
+      free(stream->orig_path);
+
+   free(stream);
+
+   return 0;
+}
+
+int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
+{
+#ifdef HAVE_CDROM
+   if (stream->scheme == VFS_SCHEME_CDROM)
+      return retro_vfs_file_error_cdrom(stream);
+#endif
+   return ferror(stream->fp);
+}
+
+int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
+{
+   if (stream)
+      return stream->size;
+   return 0;
+}
+
+int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length)
+{
+#ifdef _WIN32
+   if (stream && _chsize(_fileno(stream->fp), length) == 0)
+   {
+          stream->size = length;
+          return 0;
+   }
+#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
+   if (stream && ftruncate(fileno(stream->fp), (off_t)length) == 0)
+   {
+      stream->size = length;
+      return 0;
+   }
+#endif
+   return -1;
+}
+
+int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
+{
+   if (!stream)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+         return retro_vfs_file_tell_cdrom(stream);
+#endif
+#ifdef ATLEAST_VC2005
+      /* VC2005 and up have a special 64-bit ftell */
+      return _ftelli64(stream->fp);
+#elif defined(HAVE_64BIT_OFFSETS)
+      return ftello(stream->fp);
+#else
+      return ftell(stream->fp);
+#endif
+   }
+#ifdef HAVE_MMAP
+   /* Need to check stream->mapped because this function
+    * is called in filestream_open() */
+   if (stream->mapped && stream->hints & 
+         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+      return stream->mappos;
+#endif
+   if (lseek(stream->fd, 0, SEEK_CUR) < 0)
+      return -1;
+
+   return 0;
+}
+
+int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
+      int64_t offset, int seek_position)
+{
+   return retro_vfs_file_seek_internal(stream, offset, seek_position);
+}
+
+int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
+      void *s, uint64_t len)
+{
+   if (!stream || !s)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+         return retro_vfs_file_read_cdrom(stream, s, len);
+#endif
+      return fread(s, 1, (size_t)len, stream->fp);
+   }
+#ifdef HAVE_MMAP
+   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+   {
+      if (stream->mappos > stream->mapsize)
+         return -1;
+
+      if (stream->mappos + len > stream->mapsize)
+         len = stream->mapsize - stream->mappos;
+
+      memcpy(s, &stream->mapped[stream->mappos], len);
+      stream->mappos += len;
+
+      return len;
+   }
+#endif
+
+   return read(stream->fd, s, (size_t)len);
+}
+
+int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
+{
+   int64_t pos    = 0;
+   ssize_t result = -1;
+
+   if (!stream)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+      pos    = retro_vfs_file_tell_impl(stream);
+      result = fwrite(s, 1, (size_t)len, stream->fp);
+
+      if (result != -1 && pos + result > stream->size)
+         stream->size = pos + result;
+
+      return result;
+   }
+#ifdef HAVE_MMAP
+   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+      return -1;
+#endif
+
+   pos    = retro_vfs_file_tell_impl(stream);
+   result = write(stream->fd, s, (size_t)len);
+
+   if (result != -1 && pos + result > stream->size)
+      stream->size = pos + result;
+
+   return result;
+}
+
+int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
+{
+   if (stream && fflush(stream->fp) == 0)
+      return 0;
+   return -1;
+}
+
+int retro_vfs_file_remove_impl(const char *path)
+{
+#if defined(_WIN32) && !defined(_XBOX)
+   /* Win32 (no Xbox) */
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   char *path_local    = NULL;
+#else
+   wchar_t *path_wide  = NULL;
+#endif
+   if (!path || !*path)
+      return -1;
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   if ((path_local = utf8_to_local_string_alloc(path)))
+   {
+      int ret = remove(path_local);
+      free(path_local);
+
+      if (ret == 0)
+         return 0;
+   }
+#else
+   if ((path_wide = utf8_to_utf16_string_alloc(path)))
+   {
+      int ret = _wremove(path_wide);
+      free(path_wide);
+
+      if (ret == 0)
+         return 0;
+   }
+#endif
+#else
+   if (remove(path) == 0)
+      return 0;
+#endif
+   return -1;
+}
+
+int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
+{
+#if defined(_WIN32) && !defined(_XBOX)
+   /* Win32 (no Xbox) */
+   int ret                 = -1;
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   char *old_path_local    = NULL;
+#else
+   wchar_t *old_path_wide  = NULL;
+#endif
+
+   if (!old_path || !*old_path || !new_path || !*new_path)
+      return -1;
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   old_path_local = utf8_to_local_string_alloc(old_path);
+
+   if (old_path_local)
+   {
+      char *new_path_local = utf8_to_local_string_alloc(new_path);
+
+      if (new_path_local)
+      {
+         if (rename(old_path_local, new_path_local) == 0)
+            ret = 0;
+         free(new_path_local);
+      }
+
+      free(old_path_local);
+   }
+#else
+   old_path_wide = utf8_to_utf16_string_alloc(old_path);
+
+   if (old_path_wide)
+   {
+      wchar_t *new_path_wide = utf8_to_utf16_string_alloc(new_path);
+
+      if (new_path_wide)
+      {
+         if (_wrename(old_path_wide, new_path_wide) == 0)
+            ret = 0;
+         free(new_path_wide);
+      }
+
+      free(old_path_wide);
+   }
+#endif
+   return ret;
+
+#else
+   /* Every other platform */
+   if (!old_path || !*old_path || !new_path || !*new_path)
+      return -1;
+   return rename(old_path, new_path) == 0 ? 0 : -1;
+#endif
+}
+
+const char *retro_vfs_file_get_path_impl(
+      libretro_vfs_implementation_file *stream)
+{
+   /* should never happen, do something noisy so caller can be fixed */
+   if (!stream)
+      abort();
+   return stream->orig_path;
+}
+
+int retro_vfs_stat_impl(const char *path, int32_t *size)
+{
+   bool is_dir               = false;
+   bool is_character_special = false;
+#if defined(VITA)
+   /* Vita / PSP */
+   SceIoStat buf;
+   int dir_ret;
+   char *tmp                 = NULL;
+   size_t len                = 0;
+
+   if (!path || !*path)
+      return 0;
+
+   tmp                       = strdup(path);
+   len                       = strlen(tmp);
+   if (tmp[len-1] == '/')
+      tmp[len-1]             = '\0';
+
+   dir_ret                   = sceIoGetstat(tmp, &buf);
+   free(tmp);
+   if (dir_ret < 0)
+      return 0;
+
+   if (size)
+      *size                  = (int32_t)buf.st_size;
+
+   is_dir                    = FIO_S_ISDIR(buf.st_mode);
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   /* Lowlevel Lv2 */
+   sysFSStat buf;
+
+   if (!path || !*path)
+      return 0;
+   if (sysFsStat(path, &buf) < 0)
+      return 0;
+
+   if (size)
+      *size                  = (int32_t)buf.st_size;
+
+   is_dir                    = ((buf.st_mode & S_IFMT) == S_IFDIR);
+#elif defined(_WIN32)
+   /* Windows */
+   DWORD file_info;
+   struct _stat buf;
+#if defined(LEGACY_WIN32)
+   char *path_local          = NULL;
+#else
+   wchar_t *path_wide        = NULL;
+#endif
+
+   if (!path || !*path)
+      return 0;
+
+#if defined(LEGACY_WIN32)
+   path_local                = utf8_to_local_string_alloc(path);
+   file_info                 = GetFileAttributes(path_local);
+
+   if (!string_is_empty(path_local))
+      _stat(path_local, &buf);
+
+   if (path_local)
+      free(path_local);
+#else
+   path_wide                 = utf8_to_utf16_string_alloc(path);
+   file_info                 = GetFileAttributesW(path_wide);
+
+   _wstat(path_wide, &buf);
+
+   if (path_wide)
+      free(path_wide);
+#endif
+
+   if (file_info == INVALID_FILE_ATTRIBUTES)
+      return 0;
+
+   if (size)
+      *size = (int32_t)buf.st_size;
+
+   is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
+
+#elif defined(GEKKO)
+   /* On GEKKO platforms, paths cannot have
+    * trailing slashes - we must therefore
+    * remove them */
+   char *path_buf = NULL;
+   int stat_ret   = -1;
+   struct stat stat_buf;
+   size_t len;
+
+   if (string_is_empty(path))
+      return 0;
+
+   if (!(path_buf = strdup(path)))
+      return 0;
+
+   if ((len = strlen(path_buf)) > 0)
+      if (path_buf[len - 1] == '/')
+         path_buf[len - 1] = '\0';
+
+   stat_ret = stat(path_buf, &stat_buf);
+   free(path_buf);
+
+   if (stat_ret < 0)
+      return 0;
+
+   if (size)
+      *size             = (int32_t)stat_buf.st_size;
+
+   is_dir               = S_ISDIR(stat_buf.st_mode);
+   is_character_special = S_ISCHR(stat_buf.st_mode);
+
+#else
+   /* Every other platform */
+   struct stat buf;
+
+   if (!path || !*path)
+      return 0;
+   if (stat(path, &buf) < 0)
+      return 0;
+
+   if (size)
+      *size             = (int32_t)buf.st_size;
+
+   is_dir               = S_ISDIR(buf.st_mode);
+   is_character_special = S_ISCHR(buf.st_mode);
+#endif
+   return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
+}
+
+#if defined(VITA)
+#define path_mkdir_error(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
+#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH)
+#define path_mkdir_error(ret) ((ret) == -1)
+#else
+#define path_mkdir_error(ret) ((ret) < 0 && errno == EEXIST)
+#endif
+
+int retro_vfs_mkdir_impl(const char *dir)
+{
+#if defined(_WIN32)
+#ifdef LEGACY_WIN32
+   int ret        = _mkdir(dir);
+#else
+   wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);
+   int       ret  = -1;
+
+   if (dir_w)
+   {
+      ret = _wmkdir(dir_w);
+      free(dir_w);
+   }
+#endif
+#elif defined(IOS)
+   int ret = mkdir(dir, 0755);
+#elif defined(VITA)
+   int ret = sceIoMkdir(dir, 0777);
+#elif defined(__QNX__)
+   int ret = mkdir(dir, 0777);
+#elif defined(GEKKO) || defined(WIIU)
+   /* On GEKKO platforms, mkdir() fails if
+    * the path has a trailing slash. We must
+    * therefore remove it. */
+   int ret = -1;
+   if (!string_is_empty(dir))
+   {
+      char *dir_buf = strdup(dir);
+
+      if (dir_buf)
+      {
+         size_t len = strlen(dir_buf);
+
+         if (len > 0)
+            if (dir_buf[len - 1] == '/')
+               dir_buf[len - 1] = '\0';
+
+         ret = mkdir(dir_buf, 0750);
+
+         free(dir_buf);
+      }
+   }
+#else
+   int ret = mkdir(dir, 0750);
+#endif
+
+   if (path_mkdir_error(ret))
+      return -2;
+   return ret < 0 ? -1 : 0;
+}
+
+#ifdef VFS_FRONTEND
+struct retro_vfs_dir_handle
+#else
+struct libretro_vfs_implementation_dir
+#endif
+{
+   char* orig_path;
+#if defined(_WIN32)
+#if defined(LEGACY_WIN32)
+   WIN32_FIND_DATA entry;
+#else
+   WIN32_FIND_DATAW entry;
+#endif
+   HANDLE directory;
+   bool next;
+   char path[PATH_MAX_LENGTH];
+#elif defined(VITA)
+   SceUID directory;
+   SceIoDirent entry;
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   int error;
+   int directory;
+   sysFSDirent entry;
+#else
+   DIR *directory;
+   const struct dirent *entry;
+#endif
+};
+
+static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+   return (rdir->directory == INVALID_HANDLE_VALUE);
+#elif defined(VITA) || defined(ORBIS)
+   return (rdir->directory < 0);
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   return (rdir->error != FS_SUCCEEDED);
+#else
+   return !(rdir->directory);
+#endif
+}
+
+libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
+      const char *name, bool include_hidden)
+{
+#if defined(_WIN32)
+   char path_buf[1024];
+   size_t copied      = 0;
+#if defined(LEGACY_WIN32)
+   char *path_local   = NULL;
+#else
+   wchar_t *path_wide = NULL;
+#endif
+#endif
+   libretro_vfs_implementation_dir *rdir;
+
+   /* Reject NULL or empty string paths*/
+   if (!name || (*name == 0))
+      return NULL;
+
+   /*Allocate RDIR struct. Tidied later with retro_closedir*/
+   if (!(rdir = (libretro_vfs_implementation_dir*)
+            calloc(1, sizeof(*rdir))))
+      return NULL;
+
+   rdir->orig_path       = strdup(name);
+
+#if defined(_WIN32)
+   copied                = strlcpy(path_buf, name, sizeof(path_buf));
+
+   /* Non-NT platforms don't like extra slashes in the path */
+   if (path_buf[copied - 1] != '\\')
+      path_buf [copied++]  = '\\';
+
+   path_buf[copied  ]      = '*';
+   path_buf[copied+1]      = '\0';
+
+#if defined(LEGACY_WIN32)
+   path_local              = utf8_to_local_string_alloc(path_buf);
+   rdir->directory         = FindFirstFile(path_local, &rdir->entry);
+
+   if (path_local)
+      free(path_local);
+#else
+   path_wide               = utf8_to_utf16_string_alloc(path_buf);
+   rdir->directory         = FindFirstFileW(path_wide, &rdir->entry);
+
+   if (path_wide)
+      free(path_wide);
+#endif
+
+#elif defined(VITA)
+   rdir->directory       = sceIoDopen(name);
+#elif defined(_3DS)
+   rdir->directory       = !string_is_empty(name) ? opendir(name) : NULL;
+   rdir->entry           = NULL;
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   rdir->error           = sysFsOpendir(name, &rdir->directory);
+#else
+   rdir->directory       = opendir(name);
+   rdir->entry           = NULL;
+#endif
+
+#ifdef _WIN32
+   if (include_hidden)
+      rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+   else
+      rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
+#endif
+
+   if (rdir->directory && !dirent_check_error(rdir))
+      return rdir;
+
+   retro_vfs_closedir_impl(rdir);
+   return NULL;
+}
+
+bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+   if (rdir->next)
+#if defined(LEGACY_WIN32)
+      return (FindNextFile(rdir->directory, &rdir->entry) != 0);
+#else
+      return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
+#endif
+
+   rdir->next = true;
+   return (rdir->directory != INVALID_HANDLE_VALUE);
+#elif defined(VITA)
+   return (sceIoDread(rdir->directory, &rdir->entry) > 0);
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   uint64_t nread;
+   rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);
+   return (nread != 0);
+#else
+   return ((rdir->entry = readdir(rdir->directory)) != NULL);
+#endif
+}
+
+const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+#if defined(LEGACY_WIN32)
+   char *name       = local_to_utf8_string_alloc(rdir->entry.cFileName);
+#else
+   char *name       = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
+#endif
+   memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
+   strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
+   if (name)
+      free(name);
+   return (char*)rdir->entry.cFileName;
+#elif defined(VITA) || defined(__PSL1GHT__) || defined(__PS3__)
+   return rdir->entry.d_name;
+#else
+   if (!rdir || !rdir->entry)
+      return NULL;
+   return rdir->entry->d_name;
+#endif
+}
+
+bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+   const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
+   return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+#elif defined(VITA)
+   const SceIoDirent *entry     = (const SceIoDirent*)&rdir->entry;
+   return SCE_S_ISDIR(entry->d_stat.st_mode);
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   sysFSDirent *entry          = (sysFSDirent*)&rdir->entry;
+   return (entry->d_type == FS_TYPE_DIR);
+#else
+   struct stat buf;
+   char path[PATH_MAX_LENGTH];
+#if defined(DT_DIR)
+   const struct dirent *entry = (const struct dirent*)rdir->entry;
+   if (entry->d_type == DT_DIR)
+      return true;
+   /* This can happen on certain file systems. */
+   if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
+      return false;
+#endif
+   /* dirent struct doesn't have d_type, do it the slow way ... */
+   fill_pathname_join_special(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
+   if (stat(path, &buf) < 0)
+      return false;
+   return S_ISDIR(buf.st_mode);
+#endif
+}
+
+int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
+{
+   if (!rdir)
+      return -1;
+
+#if defined(_WIN32)
+   if (rdir->directory != INVALID_HANDLE_VALUE)
+      FindClose(rdir->directory);
+#elif defined(VITA)
+   sceIoDclose(rdir->directory);
+#elif defined(__PSL1GHT__) || defined(__PS3__)
+   rdir->error = sysFsClosedir(rdir->directory);
+#else
+   if (rdir->directory)
+      closedir(rdir->directory);
+#endif
+
+   if (rdir->orig_path)
+      free(rdir->orig_path);
+   free(rdir);
+   return 0;
+}
diff --git a/deps/libretro-common/vfs/vfs_implementation_cdrom.c b/deps/libretro-common/vfs/vfs_implementation_cdrom.c
new file mode 100644 (file)
index 0000000..093cd9c
--- /dev/null
@@ -0,0 +1,495 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation_cdrom.c).
+* ---------------------------------------------------------------------------------------
+*
+* 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 <vfs/vfs_implementation.h>
+#include <file/file_path.h>
+#include <compat/fopen_utf8.h>
+#include <string/stdstring.h>
+#include <cdrom/cdrom.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#include <windows.h>
+#endif
+
+/* TODO/FIXME - static global variable */
+static cdrom_toc_t vfs_cdrom_toc = {0};
+
+const cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)
+{
+   return &vfs_cdrom_toc;
+}
+
+int64_t retro_vfs_file_seek_cdrom(
+      libretro_vfs_implementation_file *stream,
+      int64_t offset, int whence)
+{
+   const char *ext = path_get_extension(stream->orig_path);
+
+   if (string_is_equal_noncase(ext, "cue"))
+   {
+      switch (whence)
+      {
+         case SEEK_SET:
+            stream->cdrom.byte_pos = offset;
+            break;
+         case SEEK_CUR:
+            stream->cdrom.byte_pos += offset;
+            break;
+         case SEEK_END:
+            stream->cdrom.byte_pos  = (stream->cdrom.cue_len - 1) + offset;
+            break;
+      }
+
+#ifdef CDROM_DEBUG
+      printf("[CDROM] Seek: Path %s Offset %" PRIu64 " is now at %" PRIu64 "\n",
+            stream->orig_path,
+            offset,
+            stream->cdrom.byte_pos);
+      fflush(stdout);
+#endif
+   }
+   else if (string_is_equal_noncase(ext, "bin"))
+   {
+      int lba               = (offset / 2352);
+      unsigned char min     = 0;
+      unsigned char sec     = 0;
+      unsigned char frame   = 0;
+#ifdef CDROM_DEBUG
+      const char *seek_type = "SEEK_SET";
+#endif
+
+      switch (whence)
+      {
+         case SEEK_CUR:
+            {
+               unsigned new_lba;
+#ifdef CDROM_DEBUG
+               seek_type               = "SEEK_CUR";
+#endif
+               stream->cdrom.byte_pos += offset;
+               new_lba                 = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);
+
+               cdrom_lba_to_msf(new_lba, &min, &sec, &frame);
+            }
+            break;
+         case SEEK_END:
+            {
+               ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio 
+                     ? 0 
+                     : (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));
+               ssize_t lba_len        = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;
+#ifdef CDROM_DEBUG
+               seek_type              = "SEEK_END";
+#endif
+
+               cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);
+               stream->cdrom.byte_pos = lba_len * 2352;
+            }
+            break;
+         case SEEK_SET:
+         default:
+            {
+#ifdef CDROM_DEBUG
+               seek_type = "SEEK_SET";
+#endif
+               stream->cdrom.byte_pos = offset;
+               cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);
+            }
+            break;
+      }
+
+      stream->cdrom.cur_min   = min;
+      stream->cdrom.cur_sec   = sec;
+      stream->cdrom.cur_frame = frame;
+      stream->cdrom.cur_lba   = cdrom_msf_to_lba(min, sec, frame);
+
+#ifdef CDROM_DEBUG
+      printf(
+            "[CDROM] Seek %s: Path %s Offset %" PRIu64 " is now at %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)...\n",
+            seek_type,
+            stream->orig_path,
+            offset,
+            stream->cdrom.byte_pos,
+            (unsigned)stream->cdrom.cur_min,
+            (unsigned)stream->cdrom.cur_sec,
+            (unsigned)stream->cdrom.cur_frame,
+            stream->cdrom.cur_lba);
+      fflush(stdout);
+#endif
+   }
+   else
+      return -1;
+
+   return 0;
+}
+
+void retro_vfs_file_open_cdrom(
+      libretro_vfs_implementation_file *stream,
+      const char *path, unsigned mode, unsigned hints)
+{
+#if defined(__linux__) && !defined(ANDROID)
+   char cdrom_path[]       = "/dev/sg1";
+   size_t path_len         = strlen(path);
+   const char *ext         = path_get_extension(path);
+
+   stream->cdrom.cur_track = 1;
+
+   if (     !string_is_equal_noncase(ext, "cue") 
+         && !string_is_equal_noncase(ext, "bin"))
+      return;
+
+   if (path_len >= STRLEN_CONST("drive1-track01.bin"))
+   {
+      if (!memcmp(path, "drive", STRLEN_CONST("drive")))
+      {
+         if (!memcmp(path + 6, "-track", STRLEN_CONST("-track")))
+         {
+            if (sscanf(path + 12, "%02u", (unsigned*)&stream->cdrom.cur_track))
+            {
+#ifdef CDROM_DEBUG
+               printf("[CDROM] Opening track %d\n", stream->cdrom.cur_track);
+               fflush(stdout);
+#endif
+            }
+         }
+      }
+   }
+
+   if (path_len >= STRLEN_CONST("drive1.cue"))
+   {
+      if (!memcmp(path, "drive", STRLEN_CONST("drive")))
+      {
+         if (path[5] >= '0' && path[5] <= '9')
+         {
+            cdrom_path[7]       = path[5];
+            stream->cdrom.drive = path[5];
+            vfs_cdrom_toc.drive = stream->cdrom.drive;
+         }
+      }
+   }
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
+   fflush(stdout);
+#endif
+   stream->fp = (FILE*)fopen_utf8(cdrom_path, "r+b");
+
+   if (!stream->fp)
+      return;
+
+   if (string_is_equal_noncase(ext, "cue"))
+   {
+      if (stream->cdrom.cue_buf)
+      {
+         free(stream->cdrom.cue_buf);
+         stream->cdrom.cue_buf = NULL;
+      }
+
+      cdrom_write_cue(stream,
+            &stream->cdrom.cue_buf,
+            &stream->cdrom.cue_len,
+            stream->cdrom.drive,
+            &vfs_cdrom_toc.num_tracks,
+            &vfs_cdrom_toc);
+      cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);
+
+#ifdef CDROM_DEBUG
+      if (string_is_empty(stream->cdrom.cue_buf))
+      {
+         printf("[CDROM] Error writing cue sheet.\n");
+         fflush(stdout);
+      }
+      else
+      {
+         printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
+         fflush(stdout);
+      }
+#endif
+   }
+#endif
+#if defined(_WIN32) && !defined(_XBOX)
+   char cdrom_path[] = "\\\\.\\D:";
+   size_t path_len   = strlen(path);
+   const char *ext   = path_get_extension(path);
+
+   if (     !string_is_equal_noncase(ext, "cue") 
+         && !string_is_equal_noncase(ext, "bin"))
+      return;
+
+   if (path_len >= STRLEN_CONST("d:/drive-track01.bin"))
+   {
+      if (!memcmp(path + 1, ":/drive-track", STRLEN_CONST(":/drive-track")))
+      {
+         if (sscanf(path + 14, "%02u", (unsigned*)&stream->cdrom.cur_track))
+         {
+#ifdef CDROM_DEBUG
+            printf("[CDROM] Opening track %d\n", stream->cdrom.cur_track);
+            fflush(stdout);
+#endif
+         }
+      }
+   }
+
+   if (path_len >= STRLEN_CONST("d:/drive.cue"))
+   {
+      if (!memcmp(path + 1, ":/drive", STRLEN_CONST(":/drive")))
+      {
+         if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
+         {
+            cdrom_path[4]       = path[0];
+            stream->cdrom.drive = path[0];
+            vfs_cdrom_toc.drive = stream->cdrom.drive;
+         }
+      }
+   }
+
+#ifdef CDROM_DEBUG
+   printf("[CDROM] Open: Path %s URI %s\n", cdrom_path, path);
+   fflush(stdout);
+#endif
+   stream->fh = CreateFile(cdrom_path,
+         GENERIC_READ | GENERIC_WRITE,
+         FILE_SHARE_READ | FILE_SHARE_WRITE,
+         NULL,
+         OPEN_EXISTING,
+         FILE_ATTRIBUTE_NORMAL,
+         NULL);
+
+   if (stream->fh == INVALID_HANDLE_VALUE)
+      return;
+
+   if (string_is_equal_noncase(ext, "cue"))
+   {
+      if (stream->cdrom.cue_buf)
+      {
+         free(stream->cdrom.cue_buf);
+         stream->cdrom.cue_buf = NULL;
+      }
+
+      cdrom_write_cue(stream,
+            &stream->cdrom.cue_buf,
+            &stream->cdrom.cue_len,
+            stream->cdrom.drive,
+            &vfs_cdrom_toc.num_tracks,
+            &vfs_cdrom_toc);
+      cdrom_get_timeouts(stream,
+            &vfs_cdrom_toc.timeouts);
+
+#ifdef CDROM_DEBUG
+      if (string_is_empty(stream->cdrom.cue_buf))
+      {
+         printf("[CDROM] Error writing cue sheet.\n");
+         fflush(stdout);
+      }
+      else
+      {
+         printf("[CDROM] CUE Sheet:\n%s\n", stream->cdrom.cue_buf);
+         fflush(stdout);
+      }
+#endif
+   }
+#endif
+   if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track)
+   {
+      stream->cdrom.cur_min   = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;
+      stream->cdrom.cur_sec   = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;
+      stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame;
+      stream->cdrom.cur_lba   = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
+   }
+   else
+   {
+      stream->cdrom.cur_min   = vfs_cdrom_toc.track[0].min;
+      stream->cdrom.cur_sec   = vfs_cdrom_toc.track[0].sec;
+      stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;
+      stream->cdrom.cur_lba   = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);
+   }
+}
+
+int retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream)
+{
+#ifdef CDROM_DEBUG
+   printf("[CDROM] Close: Path %s\n", stream->orig_path);
+   fflush(stdout);
+#endif
+
+#if defined(_WIN32) && !defined(_XBOX)
+   if (!stream->fh || !CloseHandle(stream->fh))
+      return -1;
+#else
+   if (!stream->fp || fclose(stream->fp))
+      return -1;
+#endif
+
+   return 0;
+}
+
+int64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)
+{
+   const char *ext = NULL;
+   if (!stream)
+      return -1;
+
+   ext = path_get_extension(stream->orig_path);
+
+   if (string_is_equal_noncase(ext, "cue"))
+   {
+#ifdef CDROM_DEBUG
+      printf("[CDROM] (cue) Tell: Path %s Position %" PRIu64 "\n", stream->orig_path, stream->cdrom.byte_pos);
+      fflush(stdout);
+#endif
+      return stream->cdrom.byte_pos;
+   }
+   else if (string_is_equal_noncase(ext, "bin"))
+   {
+#ifdef CDROM_DEBUG
+      printf("[CDROM] (bin) Tell: Path %s Position %" PRId64 "\n", stream->orig_path, stream->cdrom.byte_pos);
+      fflush(stdout);
+#endif
+      return stream->cdrom.byte_pos;
+   }
+
+   return -1;
+}
+
+int64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,
+      void *s, uint64_t len)
+{
+   int rv;
+   const char *ext = path_get_extension(stream->orig_path);
+
+   if (string_is_equal_noncase(ext, "cue"))
+   {
+      if ((int64_t)len >= (int64_t)stream->cdrom.cue_len 
+            - stream->cdrom.byte_pos)
+         len = stream->cdrom.cue_len - stream->cdrom.byte_pos - 1;
+#ifdef CDROM_DEBUG
+      printf(
+            "[CDROM] Read: Reading %" PRIu64 " bytes from cuesheet starting at %" PRIu64 "...\n",
+            len,
+            stream->cdrom.byte_pos);
+      fflush(stdout);
+#endif
+      memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len);
+      stream->cdrom.byte_pos += len;
+
+      return len;
+   }
+   else if (string_is_equal_noncase(ext, "bin"))
+   {
+      unsigned char min    = 0;
+      unsigned char sec    = 0;
+      unsigned char frame  = 0;
+      unsigned char rmin   = 0;
+      unsigned char rsec   = 0;
+      unsigned char rframe = 0;
+      size_t skip          = stream->cdrom.byte_pos % 2352;
+
+      if (stream->cdrom.byte_pos >= 
+            vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
+         return 0;
+
+      if (stream->cdrom.byte_pos + len > 
+            vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes)
+         len -= (stream->cdrom.byte_pos + len) 
+            - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;
+
+      cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);
+      cdrom_lba_to_msf(stream->cdrom.cur_lba 
+            - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba,
+            &rmin, &rsec, &rframe);
+
+#ifdef CDROM_DEBUG
+      printf(
+            "[CDROM] Read: Reading %" PRIu64 " bytes from %s starting at byte offset %" PRIu64 " (rMSF %02u:%02u:%02u aMSF %02u:%02u:%02u) (LBA %u) skip %" PRIu64 "...\n",
+            len,
+            stream->orig_path,
+            stream->cdrom.byte_pos,
+            (unsigned)rmin,
+            (unsigned)rsec,
+            (unsigned)rframe,
+            (unsigned)min,
+            (unsigned)sec,
+            (unsigned)frame,
+            stream->cdrom.cur_lba,
+            skip);
+      fflush(stdout);
+#endif
+
+#if 1
+      rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec,
+            frame, s, (size_t)len, skip);
+#else
+      rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s,
+            (size_t)len, skip);
+#endif
+
+      if (rv)
+      {
+#ifdef CDROM_DEBUG
+         printf("[CDROM] Failed to read %" PRIu64 " bytes from CD.\n", len);
+         fflush(stdout);
+#endif
+         return 0;
+      }
+
+      stream->cdrom.byte_pos += len;
+      stream->cdrom.cur_lba   = 
+         vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba 
+         + (stream->cdrom.byte_pos / 2352);
+
+      cdrom_lba_to_msf(stream->cdrom.cur_lba,
+            &stream->cdrom.cur_min,
+            &stream->cdrom.cur_sec,
+            &stream->cdrom.cur_frame);
+
+#ifdef CDROM_DEBUG
+      printf(
+            "[CDROM] read %" PRIu64 " bytes, position is now: %" PRIu64 " (MSF %02u:%02u:%02u) (LBA %u)\n",
+            len,
+            stream->cdrom.byte_pos,
+            (unsigned)stream->cdrom.cur_min,
+            (unsigned)stream->cdrom.cur_sec,
+            (unsigned)stream->cdrom.cur_frame,
+            cdrom_msf_to_lba(
+               stream->cdrom.cur_min,
+               stream->cdrom.cur_sec,
+               stream->cdrom.cur_frame)
+            );
+      fflush(stdout);
+#endif
+
+      return len;
+   }
+
+   return 0;
+}
+
+int retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)
+{
+   return 0;
+}
+
+const vfs_cdrom_t* retro_vfs_file_get_cdrom_position(
+      const libretro_vfs_implementation_file *stream)
+{
+   return &stream->cdrom;
+}
diff --git a/deps/libretro-common/vfs/vfs_implementation_uwp.cpp b/deps/libretro-common/vfs/vfs_implementation_uwp.cpp
new file mode 100644 (file)
index 0000000..5291594
--- /dev/null
@@ -0,0 +1,808 @@
+/* Copyright  (C) 2018-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation_uwp.cpp).
+* ---------------------------------------------------------------------------------------
+*
+* 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 <retro_environment.h>
+
+#include <ppl.h>
+#include <ppltasks.h>
+#include <stdio.h>
+#include <wrl.h>
+#include <wrl/implements.h>
+#include <robuffer.h>
+#include <collection.h>
+#include <functional>
+#include <fileapifromapp.h>
+#include <AclAPI.h>
+#include <sddl.h>
+#include <io.h>
+#include <fcntl.h>
+
+#ifdef RARCH_INTERNAL
+#ifndef VFS_FRONTEND
+#define VFS_FRONTEND
+#endif
+#endif
+
+#include <vfs/vfs.h>
+#include <vfs/vfs_implementation.h>
+#include <libretro.h>
+#include <encodings/utf.h>
+#include <retro_miscellaneous.h>
+#include <file/file_path.h>
+#include <string/stdstring.h>
+#include <retro_environment.h>
+#include <uwp/uwp_async.h>
+#include <uwp/std_filesystem_compat.h>
+
+namespace
+{
+   /* UWP deals with paths containing / instead of 
+    * \ way worse than normal Windows */
+   /* and RetroArch may sometimes mix them 
+    * (e.g. on archive extraction) */
+   static void windowsize_path(wchar_t* path)
+   {
+      if (path)
+      {
+         while (*path)
+         {
+            if (*path == '/')
+               *path = '\\';
+            ++path;
+         }
+      }
+   }
+}
+
+#ifdef VFS_FRONTEND
+struct retro_vfs_file_handle
+#else
+struct libretro_vfs_implementation_file
+#endif
+{
+    int64_t size;
+    uint64_t mappos;
+    uint64_t mapsize;
+    FILE* fp;
+    HANDLE fh;
+    char* buf;
+    char* orig_path;
+    uint8_t* mapped;
+    int fd;
+    unsigned hints;
+    enum vfs_scheme scheme;
+};
+
+#define RFILE_HINT_UNBUFFERED (1 << 8)
+
+int retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)
+{
+    if (!stream)
+        return -1;
+
+    if (stream->fp)
+        fclose(stream->fp);
+
+    if (stream->buf != NULL)
+    {
+        free(stream->buf);
+        stream->buf = NULL;
+    }
+    if (stream->orig_path)
+        free(stream->orig_path);
+
+    free(stream);
+
+    return 0;
+}
+
+int retro_vfs_file_error_impl(libretro_vfs_implementation_file* stream)
+{
+    return ferror(stream->fp);
+}
+
+int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file* stream)
+{
+    if (stream)
+        return stream->size;
+    return 0;
+}
+
+int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file* stream, int64_t length)
+{
+   if (stream && _chsize(_fileno(stream->fp), length) == 0)
+      return 0;
+   return -1;
+}
+
+int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)
+{
+    if (!stream)
+        return -1;
+
+    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+        return _ftelli64(stream->fp);
+    if (lseek(stream->fd, 0, SEEK_CUR) < 0)
+        return -1;
+
+    return 0;
+}
+
+int64_t retro_vfs_file_seek_internal(
+    libretro_vfs_implementation_file* stream,
+    int64_t offset, int whence)
+{
+    if (!stream)
+        return -1;
+
+    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+        return _fseeki64(stream->fp, offset, whence);
+    if (lseek(stream->fd, (off_t)offset, whence) < 0)
+        return -1;
+
+    return 0;
+}
+
+int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,
+    int64_t offset, int seek_position)
+{
+    return retro_vfs_file_seek_internal(stream, offset, seek_position);
+}
+
+int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file* stream,
+    void* s, uint64_t len)
+{
+    if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
+      return -1;
+
+   if (stream->fh != INVALID_HANDLE_VALUE)
+   {
+      DWORD _bytes_read;
+      ReadFile(stream->fh, (char*)s, len, &_bytes_read, NULL);
+      return (int64_t)_bytes_read;
+   }
+
+    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+       return fread(s, 1, (size_t)len, stream->fp);
+    return read(stream->fd, s, (size_t)len);
+}
+
+
+int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file* stream, const void* s, uint64_t len)
+{
+    if (!stream || (!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)
+        return -1;
+
+    if (stream->fh != INVALID_HANDLE_VALUE)
+    {
+        DWORD bytes_written;
+        WriteFile(stream->fh, s, len, &bytes_written, NULL);
+        return (int64_t)bytes_written;
+    }
+
+    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+        return fwrite(s, 1, (size_t)len, stream->fp);
+
+    return write(stream->fd, s, (size_t)len);
+}
+
+int retro_vfs_file_flush_impl(libretro_vfs_implementation_file* stream)
+{
+    if (stream && fflush(stream->fp) == 0)
+       return 0;
+    return -1;
+}
+
+int retro_vfs_file_remove_impl(const char *path)
+{
+   BOOL result;
+   wchar_t *path_wide;
+
+   if (!path || !*path)
+      return -1;
+
+   path_wide = utf8_to_utf16_string_alloc(path);
+   windowsize_path(path_wide);
+
+   /* Try Win32 first, this should work in AppData */
+   result = DeleteFileFromAppW(path_wide);
+   free(path_wide);
+   if (result)
+      return 0;
+
+   return -1;
+}
+
+libretro_vfs_implementation_file* retro_vfs_file_open_impl(
+    const char* path, unsigned mode, unsigned hints)
+{
+    HANDLE file_handle;
+    std::wstring path_wstring;
+    DWORD desireAccess;
+    DWORD creationDisposition;
+    wchar_t                       *path_wide = NULL;
+    int                                flags = 0;
+    const char                     *mode_str = NULL;
+    libretro_vfs_implementation_file* stream =
+        (libretro_vfs_implementation_file*)
+        malloc(sizeof(*stream));
+
+    if (!stream)
+        return NULL;
+
+    stream->fd        = 0;
+    stream->hints     = hints;
+    stream->size      = 0;
+    stream->buf       = NULL;
+    stream->fp        = NULL;
+    stream->fh        = 0;
+    stream->orig_path = NULL;
+    stream->mappos    = 0;
+    stream->mapsize   = 0;
+    stream->mapped    = NULL;
+    stream->scheme    = VFS_SCHEME_NONE;
+
+#ifdef VFS_FRONTEND
+   if (     path
+         && path[0] == 'v'
+         && path[1] == 'f'
+         && path[2] == 's'
+         && path[3] == 'o'
+         && path[4] == 'n'
+         && path[5] == 'l'
+         && path[6] == 'y'
+         && path[7] == ':'
+         && path[8] == '/'
+         && path[9] == '/')
+         path             += sizeof("vfsonly://")-1;
+#endif
+
+    path_wide    = utf8_to_utf16_string_alloc(path);
+    windowsize_path(path_wide);
+    path_wstring = path_wide;
+    free(path_wide);
+
+    for (;;)
+    {
+       size_t p = path_wstring.find(L"\\\\");
+       if (p == std::wstring::npos)
+          break;
+       path_wstring.replace(p, 2, L"\\");
+    }
+
+    path_wstring      = L"\\\\?\\" + path_wstring;
+    stream->orig_path = strdup(path);
+
+    stream->hints    &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
+
+    switch (mode)
+    {
+       case RETRO_VFS_FILE_ACCESS_READ:
+          mode_str = "rb";
+          flags    = O_RDONLY | O_BINARY;
+          break;
+
+       case RETRO_VFS_FILE_ACCESS_WRITE:
+          mode_str = "wb";
+          flags    = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
+          break;
+
+       case RETRO_VFS_FILE_ACCESS_READ_WRITE:
+          mode_str = "w+b";
+          flags    = O_RDWR | O_CREAT | O_TRUNC | O_BINARY;
+          break;
+
+       case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
+       case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
+          mode_str = "r+b";
+          flags    = O_RDWR | O_BINARY;
+          break;
+
+       default:
+          goto error;
+    }
+
+    switch (mode)
+    {
+       case RETRO_VFS_FILE_ACCESS_READ_WRITE:
+          desireAccess = GENERIC_READ | GENERIC_WRITE;
+          break;
+       case RETRO_VFS_FILE_ACCESS_WRITE:
+          desireAccess = GENERIC_WRITE;
+          break;
+       case RETRO_VFS_FILE_ACCESS_READ:
+          desireAccess = GENERIC_READ;
+          break;
+    }
+    if (mode == RETRO_VFS_FILE_ACCESS_READ)
+        creationDisposition = OPEN_EXISTING;
+    else
+        creationDisposition = (mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING) != 0 
+           ? OPEN_ALWAYS
+           : CREATE_ALWAYS;
+
+    if ((file_handle = CreateFile2FromAppW(path_wstring.data(), desireAccess,
+                FILE_SHARE_READ, creationDisposition, NULL)) == INVALID_HANDLE_VALUE)
+       goto error;
+
+    stream->fh      = file_handle;
+    if ((stream->fd = _open_osfhandle((uint64)stream->fh, flags)) == -1)
+        goto error;
+
+    {
+        FILE *fp = _fdopen(stream->fd, mode_str);
+
+        if (!fp)
+            goto error;
+        stream->fp = fp;
+    }
+
+    /* Regarding setvbuf:
+        *
+        * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
+        *
+        * If the size argument is not zero but buf is NULL,
+        * a buffer of the given size will be allocated immediately, and
+        * released on close. This is an extension to ANSI C.
+        *
+        * Since C89 does not support specifying a NULL buffer
+        * with a non-zero size, we create and track our own buffer for it.
+        */
+        /* TODO: this is only useful for a few platforms,
+        * find which and add ifdef */
+    if (stream->scheme != VFS_SCHEME_CDROM)
+    {
+        stream->buf = (char*)calloc(1, 0x4000);
+        if (stream->fp)
+            setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
+    }
+
+    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+    retro_vfs_file_seek_internal(stream, 0, SEEK_END);
+
+    stream->size = retro_vfs_file_tell_impl(stream);
+
+    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+
+    return stream;
+
+error:
+    retro_vfs_file_close_impl(stream);
+    return NULL;
+}
+
+static int uwp_mkdir_impl(std::experimental::filesystem::path dir)
+{
+    /*I feel like this should create the directory recursively but the existing implementation does not so this update won't
+     *I put in the work but I just commented out the stuff you would need */
+    WIN32_FILE_ATTRIBUTE_DATA lpFileInfo;
+    bool parent_dir_exists = false;
+
+    if (dir.empty())
+        return -1;
+
+    /* Check if file attributes can be gotten successfully  */
+    if (GetFileAttributesExFromAppW(dir.parent_path().wstring().c_str(), GetFileExInfoStandard, &lpFileInfo))
+    {
+        /* Check that the files attributes are not null or empty */
+        if (lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES && lpFileInfo.dwFileAttributes != 0)
+        {
+            if (lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                parent_dir_exists = true;
+        }
+    }
+    if (!parent_dir_exists)
+    {
+        /* Try to create parent dir */
+        int success = uwp_mkdir_impl(dir.parent_path());
+        if (success != 0 && success != -2)
+            return success;
+    }
+
+
+    /* Try Win32 first, this should work in AppData */
+    if (CreateDirectoryFromAppW(dir.wstring().c_str(), NULL))
+        return 0;
+
+    if (GetLastError() == ERROR_ALREADY_EXISTS)
+        return -2;
+
+    return -1;
+}
+
+int retro_vfs_mkdir_impl(const char* dir)
+{
+    return uwp_mkdir_impl(std::filesystem::path(dir));
+}
+
+/* The first run paramater is used to avoid error checking 
+ * when doing recursion.
+ * Unlike the initial implementation, this can move folders 
+ * even empty ones when you want to move a directory structure.
+ *
+ * This will fail even if a single file cannot be moved.
+ */
+static int uwp_move_path(
+      std::filesystem::path old_path,
+      std::filesystem::path new_path,
+      bool firstrun)
+{
+    if (old_path.empty() || new_path.empty())
+        return -1;
+
+    if (firstrun)
+    {
+        WIN32_FILE_ATTRIBUTE_DATA lpFileInfo, targetfileinfo;
+        bool parent_dir_exists = false;
+
+        /* Make sure that parent path exists */
+        if (GetFileAttributesExFromAppW(
+                 new_path.parent_path().wstring().c_str(),
+                 GetFileExInfoStandard, &lpFileInfo))
+        {
+            /* Check that the files attributes are not null or empty */
+            if (     lpFileInfo.dwFileAttributes 
+                  != INVALID_FILE_ATTRIBUTES 
+                  && lpFileInfo.dwFileAttributes != 0)
+            {
+               /* Parent path doesn't exist, so we gotta create it  */
+                if (!(lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+                    uwp_mkdir_impl(new_path.parent_path());
+            }
+        }
+
+        /* Make sure that source path exists */
+        if (GetFileAttributesExFromAppW(old_path.wstring().c_str(), GetFileExInfoStandard, &lpFileInfo))
+        {
+            /* Check that the files attributes are not null or empty */
+            if (     lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES 
+                  && lpFileInfo.dwFileAttributes != 0)
+            {
+                /* Check if source path is a dir */
+                if (lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                {
+                   int result;
+                   /* create the target dir */
+                   CreateDirectoryFromAppW(new_path.wstring().c_str(), NULL);
+                   /* Call move function again but with first run disabled in
+                    * order to move the folder */
+                   if ((result = uwp_move_path(old_path, new_path, false)) != 0)
+                      return result;
+                }
+                else
+                {
+                    /* The file that we want to move exists so we can copy it now
+                     * check if target file already exists. */
+                   if (GetFileAttributesExFromAppW(
+                            new_path.wstring().c_str(),
+                            GetFileExInfoStandard,
+                            &targetfileinfo))
+                    {
+                        if (
+                                 targetfileinfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES
+                              && targetfileinfo.dwFileAttributes != 0
+                              && (!(targetfileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
+                        {
+                            if (DeleteFileFromAppW(new_path.wstring().c_str()))
+                                return -1;
+                        }
+                    }
+
+                    if (!MoveFileFromAppW(old_path.wstring().c_str(),
+                             new_path.wstring().c_str()))
+                        return -1;
+                    /* Set ACL */
+                    uwp_set_acl(new_path.wstring().c_str(), L"S-1-15-2-1");
+                }
+            }
+        }
+
+    }
+    else
+    {
+       HANDLE searchResults;
+       WIN32_FIND_DATA findDataResult;
+       /* We are bypassing error checking and moving a dir.
+        * First we have to get a list of files in the dir. */
+       wchar_t* filteredPath = wcsdup(old_path.wstring().c_str());
+       wcscat_s(filteredPath, sizeof(L"\\*.*"), L"\\*.*");
+       searchResults         = FindFirstFileExFromAppW(
+             filteredPath, FindExInfoBasic, &findDataResult,
+             FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
+
+       if (searchResults != INVALID_HANDLE_VALUE)
+       {
+          bool fail = false;
+          do
+          {
+             if (     wcscmp(findDataResult.cFileName, L".")  != 0 
+                   && wcscmp(findDataResult.cFileName, L"..") != 0)
+             {
+                std::filesystem::path temp_old = old_path;
+                std::filesystem::path temp_new = new_path;
+                temp_old /= findDataResult.cFileName;
+                temp_new /= findDataResult.cFileName;
+                if (    findDataResult.dwFileAttributes 
+                      & FILE_ATTRIBUTE_DIRECTORY)
+                {
+                   CreateDirectoryFromAppW(temp_new.wstring().c_str(), NULL);
+                   if (uwp_move_path(temp_old, temp_new, false) != 0)
+                      fail = true;
+                }
+                else
+                {
+                   WIN32_FILE_ATTRIBUTE_DATA targetfileinfo;
+                   /* The file that we want to move exists so we can copy
+                    * it now.
+                    * Check if target file already exists. */
+                   if (GetFileAttributesExFromAppW(temp_new.wstring().c_str(),
+                            GetFileExInfoStandard, &targetfileinfo))
+                   {
+                      if (
+                               (targetfileinfo.dwFileAttributes !=
+                                INVALID_FILE_ATTRIBUTES)
+                            && (targetfileinfo.dwFileAttributes != 0)
+                            && (!(targetfileinfo.dwFileAttributes 
+                                  & FILE_ATTRIBUTE_DIRECTORY)))
+                      {
+                         if (DeleteFileFromAppW(temp_new.wstring().c_str()))
+                            fail = true;
+                      }
+                   }
+
+                   if (!MoveFileFromAppW(temp_old.wstring().c_str(),
+                            temp_new.wstring().c_str()))
+                      fail = true;
+                   /* Set ACL - this step sucks or at least used to 
+                    * before I made a whole function
+                    * Don't know if we actually "need" to set the ACL
+                    * though */
+                   uwp_set_acl(temp_new.wstring().c_str(), L"S-1-15-2-1");
+                }
+             }
+          } while (FindNextFile(searchResults, &findDataResult));
+          FindClose(searchResults);
+          if (fail)
+             return -1;
+       }
+       free(filteredPath);
+    }
+    return 0;
+}
+
+/* C doesn't support default arguments so we wrap it up in a shell to enable 
+ * us to use default arguments.
+ * Default arguments mean that we can do better recursion */
+int retro_vfs_file_rename_impl(const char* old_path, const char* new_path)
+{
+    return uwp_move_path(std::filesystem::path(old_path),
+          std::filesystem::path(old_path), true);
+}
+
+const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream)
+{
+   /* Should never happen, do something noisy so caller can be fixed */
+   if (!stream)
+      abort();
+   return stream->orig_path;
+}
+
+int retro_vfs_stat_impl(const char *path, int32_t *size)
+{
+   wchar_t *path_wide;
+   _WIN32_FILE_ATTRIBUTE_DATA attribdata;
+
+   if (!path || !*path)
+      return 0;
+
+   path_wide = utf8_to_utf16_string_alloc(path);
+   windowsize_path(path_wide);
+
+   /* Try Win32 first, this should work in AppData */
+   if (GetFileAttributesExFromAppW(path_wide,
+            GetFileExInfoStandard, &attribdata))
+   {
+       if (attribdata.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
+       {
+           if (!(attribdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+           {
+               LARGE_INTEGER sz;
+               if (size)
+               {
+                   sz.HighPart = attribdata.nFileSizeHigh;
+                   sz.LowPart = attribdata.nFileSizeLow;
+                   *size = sz.QuadPart;
+               }
+           }
+           free(path_wide);
+           return (attribdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 
+              ? RETRO_VFS_STAT_IS_VALID | RETRO_VFS_STAT_IS_DIRECTORY 
+              : RETRO_VFS_STAT_IS_VALID;
+       }
+   }
+   free(path_wide);
+   return 0;
+}
+
+#ifdef VFS_FRONTEND
+struct retro_vfs_dir_handle
+#else
+struct libretro_vfs_implementation_dir
+#endif
+{
+    char* orig_path;
+    WIN32_FIND_DATAW entry;
+    HANDLE directory;
+    bool next;
+    char path[PATH_MAX_LENGTH];
+};
+
+libretro_vfs_implementation_dir* retro_vfs_opendir_impl(
+    const char* name, bool include_hidden)
+{
+    char path_buf[1024];
+    size_t copied      = 0;
+    wchar_t* path_wide = NULL;
+    libretro_vfs_implementation_dir* rdir;
+
+    /* Reject NULL or empty string paths*/
+    if (!name || (*name == 0))
+        return NULL;
+
+    /*Allocate RDIR struct. Tidied later with retro_closedir*/
+    if (!(rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir))))
+        return NULL;
+
+    rdir->orig_path = strdup(name);
+
+    copied          = strlcpy(path_buf, name, sizeof(path_buf));
+
+    /* Non-NT platforms don't like extra slashes in the path */
+    if (path_buf[copied - 1] != '\\')
+        path_buf[copied++] = '\\';
+
+    path_buf[copied]       = '*';
+    path_buf[copied + 1]   = '\0';
+
+    path_wide              = utf8_to_utf16_string_alloc(path_buf);
+    rdir->directory        = FindFirstFileExFromAppW(
+          path_wide, FindExInfoStandard, &rdir->entry,
+          FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
+
+    if (path_wide)
+        free(path_wide);
+
+    if (include_hidden)
+        rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+    else
+        rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
+
+    if (rdir->directory && rdir != INVALID_HANDLE_VALUE)
+        return rdir;
+
+    retro_vfs_closedir_impl(rdir);
+    return NULL;
+}
+
+bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)
+{
+    if (rdir->next)
+        return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
+
+    rdir->next = true;
+    return (rdir->directory != INVALID_HANDLE_VALUE);
+}
+
+const char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir)
+{
+    char* name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
+    memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
+    strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
+    if (name)
+        free(name);
+    return (char*)rdir->entry.cFileName;
+}
+
+bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir* rdir)
+{
+    const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry;
+    return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+}
+
+int retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)
+{
+    if (!rdir)
+        return -1;
+
+    if (rdir->directory != INVALID_HANDLE_VALUE)
+        FindClose(rdir->directory);
+
+    if (rdir->orig_path)
+        free(rdir->orig_path);
+    free(rdir);
+    return 0;
+}
+
+void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString)
+{
+    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
+    EXPLICIT_ACCESSW ExplicitAccess         = { 0 };
+    ACL* AccessControlCurrent               = NULL;
+    ACL* AccessControlNew                   = NULL;
+    SECURITY_INFORMATION SecurityInfo       = DACL_SECURITY_INFORMATION;
+    PSID SecurityIdentifier                 = NULL;
+    HANDLE original_file                    = CreateFileFromAppW(path,
+          GENERIC_READ    | GENERIC_WRITE | WRITE_DAC,
+          FILE_SHARE_READ | FILE_SHARE_WRITE,
+          NULL, OPEN_EXISTING, 0, NULL);
+
+    if (original_file != INVALID_HANDLE_VALUE)
+    {
+       if (
+             GetSecurityInfo(
+                original_file,
+                SE_FILE_OBJECT,
+                DACL_SECURITY_INFORMATION,
+                NULL,
+                NULL,
+                &AccessControlCurrent,
+                NULL,
+                &SecurityDescriptor
+                ) == ERROR_SUCCESS
+          )
+       {
+          ConvertStringSidToSidW(AccessString, &SecurityIdentifier);
+          if (SecurityIdentifier)
+          {
+             ExplicitAccess.grfAccessPermissions= GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE;
+             ExplicitAccess.grfAccessMode       = SET_ACCESS;
+             ExplicitAccess.grfInheritance      = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+             ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+             ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
+             ExplicitAccess.Trustee.ptstrName   = reinterpret_cast<wchar_t*>(SecurityIdentifier);
+
+             if (
+                   SetEntriesInAclW(
+                      1,
+                      &ExplicitAccess,
+                      AccessControlCurrent,
+                      &AccessControlNew
+                      ) == ERROR_SUCCESS
+                )
+                SetSecurityInfo(
+                      original_file,
+                      SE_FILE_OBJECT,
+                      SecurityInfo,
+                      NULL,
+                      NULL,
+                      AccessControlNew,
+                      NULL
+                      );
+          }
+       }
+       if (SecurityDescriptor)
+          LocalFree(reinterpret_cast<HLOCAL>(SecurityDescriptor));
+       if (AccessControlNew)
+          LocalFree(reinterpret_cast<HLOCAL>(AccessControlNew));
+       CloseHandle(original_file);
+    }
+}
diff --git a/deps/libretro-common/vulkan/vulkan_symbol_wrapper.c b/deps/libretro-common/vulkan/vulkan_symbol_wrapper.c
new file mode 100644 (file)
index 0000000..f816bdc
--- /dev/null
@@ -0,0 +1,482 @@
+
+/* This header is autogenerated by vulkan_loader_generator.py */
+#include <vulkan/vulkan_symbol_wrapper.h>
+
+PFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;
+PFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;
+PFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;
+PFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;
+PFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;
+PFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;
+PFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;
+PFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;
+PFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;
+PFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;
+PFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;
+PFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;
+PFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;
+PFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;
+PFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;
+PFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;
+PFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;
+PFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;
+PFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;
+PFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;
+PFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;
+PFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;
+PFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;
+PFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;
+PFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;
+PFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;
+PFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;
+PFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;
+PFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;
+PFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;
+PFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;
+PFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;
+PFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;
+PFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;
+PFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;
+PFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;
+PFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;
+PFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;
+PFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;
+PFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;
+PFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;
+PFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;
+PFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;
+PFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;
+PFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;
+PFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;
+PFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;
+PFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;
+PFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;
+PFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;
+PFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;
+PFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;
+PFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;
+PFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;
+PFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;
+PFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;
+PFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;
+PFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;
+PFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;
+PFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;
+PFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;
+PFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;
+PFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;
+PFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;
+PFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;
+PFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;
+PFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;
+PFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;
+PFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;
+PFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;
+PFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;
+PFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;
+PFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;
+PFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;
+PFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;
+PFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;
+PFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;
+PFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;
+PFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;
+PFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;
+PFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;
+PFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;
+PFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;
+PFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;
+PFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;
+PFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;
+PFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;
+PFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;
+PFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;
+PFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;
+PFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;
+PFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;
+PFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;
+PFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;
+PFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;
+PFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;
+PFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;
+PFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;
+PFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;
+PFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;
+PFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;
+PFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;
+PFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;
+PFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;
+PFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;
+PFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;
+PFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;
+PFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;
+PFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;
+PFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;
+PFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;
+PFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;
+PFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;
+PFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;
+PFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;
+PFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;
+PFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;
+PFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;
+PFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;
+PFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;
+PFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;
+PFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;
+PFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;
+PFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;
+PFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;
+PFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;
+PFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;
+PFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;
+PFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;
+PFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;
+PFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;
+PFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;
+PFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;
+PFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;
+PFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;
+PFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;
+PFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;
+PFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;
+PFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;
+PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
+PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;
+PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;
+PFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;
+PFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;
+PFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;
+PFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;
+PFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;
+PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;
+PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
+PFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;
+PFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;
+PFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;
+PFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;
+PFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;
+PFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;
+
+PFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;
+PFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;
+PFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;
+
+static PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+void vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr)
+{
+    GetInstanceProcAddr = get_instance_proc_addr;
+}
+
+PFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void)
+{
+    return GetInstanceProcAddr;
+}
+
+VkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol)
+{
+    *ppSymbol = GetInstanceProcAddr(instance, name);
+    return *ppSymbol != NULL;
+}
+
+VkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol)
+{
+    *ppSymbol = vkGetDeviceProcAddr(device, name);
+    return *ppSymbol != NULL;
+}
+
+VkBool32 vulkan_symbol_wrapper_load_global_symbols(void)
+{
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkCreateInstance", vkCreateInstance)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceExtensionProperties", vkEnumerateInstanceExtensionProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceLayerProperties", vkEnumerateInstanceLayerProperties)) return VK_FALSE;
+    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, "vkEnumerateInstanceVersion", vkEnumerateInstanceVersion);
+    return VK_TRUE;
+}
+
+VkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance)
+{
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyInstance", vkDestroyInstance)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumeratePhysicalDevices", vkEnumeratePhysicalDevices)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFeatures", vkGetPhysicalDeviceFeatures)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFormatProperties", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceImageFormatProperties", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceProperties", vkGetPhysicalDeviceProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceQueueFamilyProperties", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceMemoryProperties", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceProcAddr", vkGetDeviceProcAddr)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDevice", vkCreateDevice)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDevice", vkDestroyDevice)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceExtensionProperties", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceLayerProperties", vkEnumerateDeviceLayerProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceQueue", vkGetDeviceQueue)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueSubmit", vkQueueSubmit)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueWaitIdle", vkQueueWaitIdle)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDeviceWaitIdle", vkDeviceWaitIdle)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateMemory", vkAllocateMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeMemory", vkFreeMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkMapMemory", vkMapMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkUnmapMemory", vkUnmapMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFlushMappedMemoryRanges", vkFlushMappedMemoryRanges)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceMemoryCommitment", vkGetDeviceMemoryCommitment)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBindBufferMemory", vkBindBufferMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBindImageMemory", vkBindImageMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetBufferMemoryRequirements", vkGetBufferMemoryRequirements)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageMemoryRequirements", vkGetImageMemoryRequirements)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageSparseMemoryRequirements", vkGetImageSparseMemoryRequirements)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceSparseImageFormatProperties", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkQueueBindSparse", vkQueueBindSparse)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateFence", vkCreateFence)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyFence", vkDestroyFence)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetFences", vkResetFences)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetFenceStatus", vkGetFenceStatus)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkWaitForFences", vkWaitForFences)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateSemaphore", vkCreateSemaphore)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroySemaphore", vkDestroySemaphore)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateEvent", vkCreateEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyEvent", vkDestroyEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetEventStatus", vkGetEventStatus)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkSetEvent", vkSetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetEvent", vkResetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateQueryPool", vkCreateQueryPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyQueryPool", vkDestroyQueryPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetQueryPoolResults", vkGetQueryPoolResults)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateBuffer", vkCreateBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyBuffer", vkDestroyBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateBufferView", vkCreateBufferView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyBufferView", vkDestroyBufferView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateImage", vkCreateImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyImage", vkDestroyImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetImageSubresourceLayout", vkGetImageSubresourceLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateImageView", vkCreateImageView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyImageView", vkDestroyImageView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateShaderModule", vkCreateShaderModule)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyShaderModule", vkDestroyShaderModule)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreatePipelineCache", vkCreatePipelineCache)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipelineCache", vkDestroyPipelineCache)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPipelineCacheData", vkGetPipelineCacheData)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkMergePipelineCaches", vkMergePipelineCaches)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateGraphicsPipelines", vkCreateGraphicsPipelines)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateComputePipelines", vkCreateComputePipelines)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipeline", vkDestroyPipeline)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreatePipelineLayout", vkCreatePipelineLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyPipelineLayout", vkDestroyPipelineLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateSampler", vkCreateSampler)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroySampler", vkDestroySampler)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDescriptorSetLayout", vkCreateDescriptorSetLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDescriptorSetLayout", vkDestroyDescriptorSetLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDescriptorPool", vkCreateDescriptorPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyDescriptorPool", vkDestroyDescriptorPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetDescriptorPool", vkResetDescriptorPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateDescriptorSets", vkAllocateDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeDescriptorSets", vkFreeDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkUpdateDescriptorSets", vkUpdateDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateFramebuffer", vkCreateFramebuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyFramebuffer", vkDestroyFramebuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateRenderPass", vkCreateRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyRenderPass", vkDestroyRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetRenderAreaGranularity", vkGetRenderAreaGranularity)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateCommandPool", vkCreateCommandPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyCommandPool", vkDestroyCommandPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetCommandPool", vkResetCommandPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkAllocateCommandBuffers", vkAllocateCommandBuffers)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkFreeCommandBuffers", vkFreeCommandBuffers)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkBeginCommandBuffer", vkBeginCommandBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEndCommandBuffer", vkEndCommandBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkResetCommandBuffer", vkResetCommandBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindPipeline", vkCmdBindPipeline)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetViewport", vkCmdSetViewport)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetScissor", vkCmdSetScissor)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetLineWidth", vkCmdSetLineWidth)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetDepthBias", vkCmdSetDepthBias)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetBlendConstants", vkCmdSetBlendConstants)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetDepthBounds", vkCmdSetDepthBounds)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilCompareMask", vkCmdSetStencilCompareMask)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilWriteMask", vkCmdSetStencilWriteMask)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetStencilReference", vkCmdSetStencilReference)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindDescriptorSets", vkCmdBindDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindIndexBuffer", vkCmdBindIndexBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBindVertexBuffers", vkCmdBindVertexBuffers)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDraw", vkCmdDraw)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndexed", vkCmdDrawIndexed)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndirect", vkCmdDrawIndirect)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDrawIndexedIndirect", vkCmdDrawIndexedIndirect)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDispatch", vkCmdDispatch)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdDispatchIndirect", vkCmdDispatchIndirect)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyBuffer", vkCmdCopyBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyImage", vkCmdCopyImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBlitImage", vkCmdBlitImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyBufferToImage", vkCmdCopyBufferToImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyImageToBuffer", vkCmdCopyImageToBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdUpdateBuffer", vkCmdUpdateBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdFillBuffer", vkCmdFillBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearColorImage", vkCmdClearColorImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearDepthStencilImage", vkCmdClearDepthStencilImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdClearAttachments", vkCmdClearAttachments)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResolveImage", vkCmdResolveImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdSetEvent", vkCmdSetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResetEvent", vkCmdResetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdWaitEvents", vkCmdWaitEvents)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdPipelineBarrier", vkCmdPipelineBarrier)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBeginQuery", vkCmdBeginQuery)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdEndQuery", vkCmdEndQuery)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdResetQueryPool", vkCmdResetQueryPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdWriteTimestamp", vkCmdWriteTimestamp)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdCopyQueryPoolResults", vkCmdCopyQueryPoolResults)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdPushConstants", vkCmdPushConstants)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdBeginRenderPass", vkCmdBeginRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdNextSubpass", vkCmdNextSubpass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdEndRenderPass", vkCmdEndRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCmdExecuteCommands", vkCmdExecuteCommands)) return VK_FALSE;
+    return VK_TRUE;
+}
+
+VkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance)
+{
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkDestroyInstance", vkDestroyInstance)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumeratePhysicalDevices", vkEnumeratePhysicalDevices)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFeatures", vkGetPhysicalDeviceFeatures)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceFormatProperties", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceImageFormatProperties", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceProperties", vkGetPhysicalDeviceProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceQueueFamilyProperties", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceMemoryProperties", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetDeviceProcAddr", vkGetDeviceProcAddr)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkCreateDevice", vkCreateDevice)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceExtensionProperties", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkEnumerateDeviceLayerProperties", vkEnumerateDeviceLayerProperties)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, "vkGetPhysicalDeviceSparseImageFormatProperties", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;
+    return VK_TRUE;
+}
+
+VkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device)
+{
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDevice", vkDestroyDevice)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetDeviceQueue", vkGetDeviceQueue)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueSubmit", vkQueueSubmit)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueWaitIdle", vkQueueWaitIdle)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDeviceWaitIdle", vkDeviceWaitIdle)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateMemory", vkAllocateMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeMemory", vkFreeMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkMapMemory", vkMapMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkUnmapMemory", vkUnmapMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFlushMappedMemoryRanges", vkFlushMappedMemoryRanges)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetDeviceMemoryCommitment", vkGetDeviceMemoryCommitment)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBindBufferMemory", vkBindBufferMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBindImageMemory", vkBindImageMemory)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetBufferMemoryRequirements", vkGetBufferMemoryRequirements)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageMemoryRequirements", vkGetImageMemoryRequirements)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageSparseMemoryRequirements", vkGetImageSparseMemoryRequirements)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkQueueBindSparse", vkQueueBindSparse)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateFence", vkCreateFence)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyFence", vkDestroyFence)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetFences", vkResetFences)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetFenceStatus", vkGetFenceStatus)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkWaitForFences", vkWaitForFences)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateSemaphore", vkCreateSemaphore)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroySemaphore", vkDestroySemaphore)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateEvent", vkCreateEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyEvent", vkDestroyEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetEventStatus", vkGetEventStatus)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkSetEvent", vkSetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetEvent", vkResetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateQueryPool", vkCreateQueryPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyQueryPool", vkDestroyQueryPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetQueryPoolResults", vkGetQueryPoolResults)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateBuffer", vkCreateBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyBuffer", vkDestroyBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateBufferView", vkCreateBufferView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyBufferView", vkDestroyBufferView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateImage", vkCreateImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyImage", vkDestroyImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetImageSubresourceLayout", vkGetImageSubresourceLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateImageView", vkCreateImageView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyImageView", vkDestroyImageView)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateShaderModule", vkCreateShaderModule)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyShaderModule", vkDestroyShaderModule)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreatePipelineCache", vkCreatePipelineCache)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipelineCache", vkDestroyPipelineCache)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetPipelineCacheData", vkGetPipelineCacheData)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkMergePipelineCaches", vkMergePipelineCaches)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateGraphicsPipelines", vkCreateGraphicsPipelines)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateComputePipelines", vkCreateComputePipelines)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipeline", vkDestroyPipeline)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreatePipelineLayout", vkCreatePipelineLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyPipelineLayout", vkDestroyPipelineLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateSampler", vkCreateSampler)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroySampler", vkDestroySampler)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateDescriptorSetLayout", vkCreateDescriptorSetLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDescriptorSetLayout", vkDestroyDescriptorSetLayout)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateDescriptorPool", vkCreateDescriptorPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyDescriptorPool", vkDestroyDescriptorPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetDescriptorPool", vkResetDescriptorPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateDescriptorSets", vkAllocateDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeDescriptorSets", vkFreeDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkUpdateDescriptorSets", vkUpdateDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateFramebuffer", vkCreateFramebuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyFramebuffer", vkDestroyFramebuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateRenderPass", vkCreateRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyRenderPass", vkDestroyRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkGetRenderAreaGranularity", vkGetRenderAreaGranularity)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCreateCommandPool", vkCreateCommandPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkDestroyCommandPool", vkDestroyCommandPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetCommandPool", vkResetCommandPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkAllocateCommandBuffers", vkAllocateCommandBuffers)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkFreeCommandBuffers", vkFreeCommandBuffers)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkBeginCommandBuffer", vkBeginCommandBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkEndCommandBuffer", vkEndCommandBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkResetCommandBuffer", vkResetCommandBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindPipeline", vkCmdBindPipeline)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetViewport", vkCmdSetViewport)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetScissor", vkCmdSetScissor)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetLineWidth", vkCmdSetLineWidth)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetDepthBias", vkCmdSetDepthBias)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetBlendConstants", vkCmdSetBlendConstants)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetDepthBounds", vkCmdSetDepthBounds)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilCompareMask", vkCmdSetStencilCompareMask)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilWriteMask", vkCmdSetStencilWriteMask)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetStencilReference", vkCmdSetStencilReference)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindDescriptorSets", vkCmdBindDescriptorSets)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindIndexBuffer", vkCmdBindIndexBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBindVertexBuffers", vkCmdBindVertexBuffers)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDraw", vkCmdDraw)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndexed", vkCmdDrawIndexed)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndirect", vkCmdDrawIndirect)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDrawIndexedIndirect", vkCmdDrawIndexedIndirect)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDispatch", vkCmdDispatch)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdDispatchIndirect", vkCmdDispatchIndirect)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyBuffer", vkCmdCopyBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyImage", vkCmdCopyImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBlitImage", vkCmdBlitImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyBufferToImage", vkCmdCopyBufferToImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyImageToBuffer", vkCmdCopyImageToBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdUpdateBuffer", vkCmdUpdateBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdFillBuffer", vkCmdFillBuffer)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearColorImage", vkCmdClearColorImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearDepthStencilImage", vkCmdClearDepthStencilImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdClearAttachments", vkCmdClearAttachments)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResolveImage", vkCmdResolveImage)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdSetEvent", vkCmdSetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResetEvent", vkCmdResetEvent)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdWaitEvents", vkCmdWaitEvents)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdPipelineBarrier", vkCmdPipelineBarrier)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBeginQuery", vkCmdBeginQuery)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdEndQuery", vkCmdEndQuery)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdResetQueryPool", vkCmdResetQueryPool)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdWriteTimestamp", vkCmdWriteTimestamp)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdCopyQueryPoolResults", vkCmdCopyQueryPoolResults))
+    {
+#if 0
+       /* Don't return false here. Would cause MESA Intel Ivy Bridge drivers to not work at all. */
+       return VK_FALSE;
+#endif
+    }
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdPushConstants", vkCmdPushConstants)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdBeginRenderPass", vkCmdBeginRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdNextSubpass", vkCmdNextSubpass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdEndRenderPass", vkCmdEndRenderPass)) return VK_FALSE;
+    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, "vkCmdExecuteCommands", vkCmdExecuteCommands)) return VK_FALSE;
+    return VK_TRUE;
+}